Gidhub BE Developer

DB 컬럼(Column) 타입 차이 알아보기 : CHAR vs VARCHAR 비교 및 특징

2021-11-13
goodGid
DB

CHAR

공백 처리

  • CHAR는 고정 사이즈이다.

  • 남는 공간은 공백으로 채우게 된다.

  • 공백 채움 비교(blank-padded comparison semantics)를 사용한다.

    예를 들어 CHAR(10) 인 데

    ‘test’라는 4자짜리 문자열을 insert 하게 되면

    남는 공간은 6개의 공백으로 채우게 된다.

    따라서 무조건 처음 선언된 10byte가 소요된다.

  • 물론 값을 받아 올 때 이 공백은 자동으로 제거된다.

    공백까지 읽고 싶다면 PAD_CHAR_TO_FULL_LENGTH 모드를 활성화하면 공백까지 다 읽어온다.

  • if ( 저장할 데이터 길이 < 선언된 컬럼 길이 )

    -> 남는 공간은 스페이스로 채워지므로 공간의 낭비가 발생한다.

    따라서 반드시 고정길이에 해당하는 데이터만 CHAR로 선언하는 것이 좋다.


VARCHAR

길이 정보

  • VARCHAR는 이름이 의미하듯 가변 길이이다.

  • 데이터를 삽입 시

    데이터값외에 삽입된 문자열의 길이를 저장하는데

    255글자 이하에는 1바이트

    그 이상은 2바이트의 추가 공간을 필요로 한다.

    즉 실질적인 데이터와 길이 정보도 같이 저장된다.

  • 예를 들어 VARCHAR(10)에

    ‘test’라는 4자짜리 문자열을 삽입하면

    4byte + 1byte(길이를 저장하기 위한 메모리) = 5byte가 소모된다.

  • 저장할 수 있는 길이는 0부터 255까지이며

    MySQL 5.0.3 이후에는 0부터 65,535까지 지정할 수 있다.


공백 처리

  • 기본적으로 VARCHAR 값은 저장 시 공백이 추가되지 않는다.

    하지만 공백에 대한 처리는 버전에 따라 다르다.

  • if ( MySQL 5.0.3 이후 )

    -> 저장 시 공백들 제거 X && Read 시 공백 보존

  • if ( MySQL 5.0.3 이전 )

    -> 저장 시 공백들 유지 && Read 시 공백 유지

  • MySQL 5.0.3 이전에 뒤따르는 공백들을 유지하기 위해서는

    BLOB나 TEXT 형을 선택해야 했다.


데이터 파편화

  • 만약 저장된 값을 변경하려고 하는데

    변경할 값이 저장된 사이즈보다 클 땐 데이터 파편화가 발생한다.

Why?

기존보다 큰 데이터를 저장하기 위해서 
새로운 저장 영역에 새로 할당해야 하므로 데이터 파편화가 발생한다.

  • 테이블 ROW 중에 CHAR, VARCHAR 타입이

    섞여 있으면 데이터 파편화는 발생할 수밖에 없다.

  • 파편화를 염두에 두고 설계한다면

    테이블의 데이터 타입 중에 VARCHAR 타입을 사용해선 안 된다.

  • 그러나 MySQL에서는 다음의 쿼리를 적용하면 파편화를 막을 수 있다.

    ALTER TABLE tblname ROW_FORMAT = FIXED;

  • VARCHAR 타입을 CHAR 타입처럼 동작하도록 강제로 지정하는 것이다.

    CHAR처럼 동작하기 때문에 데이터 용량은 증가하지만

    VARCHAR로 인한 파편화로 성능 저하는 막을 수 있다.


4글자 이하 자동 변환

  • 4글자 이하의 VARCHAR는 CHAR로 자동 변환된다.

  • 만약 테이블 안에 VARCHAR나 text, blob 같은 가변 길이 데이터가 하나라도 있으면

    3자 이상의 CHAR컬럼이 자동으로 VARCHAR로 바뀌게 된다.

  • TABLE을 만든 후 실제로 무슨 형으로 변환되었는지 DESC table_name으로 확인할 수 있다.

  • 이렇게 하는 이유는 성능과 속도 때문이다.

Q. 그렇다면 모두 VARCHAR를 사용하지 않는 이유는 무엇일까?

  • 무조건 VARCHAR를 사용 시 가변이기 때문에

    내부에서 추가적인 Logic이 발생하여 속도 저하를 일으킬 수 있다.


CHAR와 VARCHAR의 비교

저장 영역

  1. CHAR형은 고정형

    최대 길이는 255

  2. VARCHAR형은 가변형

    최대 길이는 255

    MySQL 5.0.3 이후부터는 65,535까지 가능

  3. MySQL 4.1 이후 버전부터는

    CHAR(n), VARCHAR(n)에서 n은 바이트가 아니라 글자 수를 의미한다.

    ex) CHAR(30)은 30 글자까지 보관할 수 있다.

  • VARCHAR 유형은 가변 길이이므로 필요한 영역은 실제 데이터 크기뿐이다.

    그렇기 때문에 길이가 다양한 컬럼과

    정의된 길이와 실제 데이터 길이에 차이가 있는 컬럼에 적합하다.

  • 저장 측면에서도 CHAR 유형보다 작은 영역에 저장할 수 있으므로 장점이 있다.


비교 방법

  • CHAR에서는 문자열을 비교할 때 공백을 채워서 비교하는 방법을 사용한다.

  • CHAR(8)이고 ‘AA’가 저장되어 있다면

    ‘AA’ 뒤에 공백 6자리를 붙여 8자리로 비교하는 것이다.

따라서  'AA' = 'AA  '은 
실제로 'AA      ' = 'AA      '가 되어 같다는 결과가 나온다.
  • 반면 VARCHAR에서는

    공백도 하나의 문자로 취급하므로 끝에 공백이 들어가면 다른 문자로 판단한다.

같은 예로 
'AA' != 'AA '로 공백이 있어 서로 다른 문자로 판단한다.
  • 따라서 이름, 주소 등의 길이가 변할 수 있는 값은 VARCHAR를 사용하고

    사번, 주민등록번호와 같이 길이가 일정한 데이터는 CHAR를 사용하는 게 좋다.


속도 측면

  • Fixed table vs Dynamic table의 속도 차이를 테스트해보자.

  • 아래와 같이 2개의 테이블을 만들고

create table variable (
one int primary key,
two VARCHAR(10),
three VARCHAR(30) );

create table fixed (
one int primary key,
two CHAR(10),
three CHAR(30) );
  • 10만건의 자료를

    insert 후 select 속도를 비교한 결과를 보면 다음과 같다.

-- select는 table full scan
-- 2개의 쿼리를 사용
"select * from variable"
"select * from fixed"
  • CHAR를 사용했을 때는 0.54 sec가 걸렸으며

    VARCHAR를 사용했을 때는 0.64 sec가 걸렸다.

  • 즉 Fixed type table(고정길이 테이블)을 사용할 경우 0.1 sec가 더 빨랐다.

  • 겨우 0.1초라고 생각할 수도 있으나

    동시에 100개의 접속이 들어올 경우를 가정한다면 무시할 수 없는 속도 차이이다.

  • 정리하자면 VARCHAR형의 경우

    일일이 그 길이를 계산하여야 다음 ROW를 얻을 수 있지만

    CHAR형의 경우는 항상 고정된 ROW 사이즈를 가지고 있으므로

    얻고자하는 ROW를 찾아내는데 훨씬 빠르다.


Strict SQL Mode

  • 엄격한 SQL 모드(strict SQL mode)가 활성화되지 않은 상태에서

    열의 최대 길이를 초과하여 값을 저장하면

    값을 잘라서 보관하고 경고를 발생시킨다.

  • 엄격한 SQL 모드를 활성화하면

    공백이 아닌 문자열을 자를 때 경고 대신

    에러를 발생시키고 값을 추가하지 못하도록 할 수 있다.

  • VARCHAR일 경우 해당 열의 길이를 초과하는 공백들은

    SQL 모드에 관계없이 잘린 후 저장되며 경고를 발생시킨다.

  • CHAR일 경우에는 마찬가지로 동작하지만 경고가 발생하지 않는다.


  • 다음 표는 문자열을

    CHAR(4)와 VARCHAR(4) 열에 보관 시

    CHAR와 VARCHAR형의 차이점을 보여준다.

  • 마지막 열의 값은 엄격한 SQL 모드를 사용하지 않을 때만 적용된다.

  • 만약 엄격한 SQL 모드로

    MySQL이 동작한다면 길이를 초과하는 값을 저장되지 않고 에러를 발생시키게 된다.


Reference


Index