1. CHAR 형
-
고정 사이즈.
-
남는 공간은 공백으로 채운다.
공백 채움 비교(blank-padded comparison semantics)를 사용하여
CHAR(10) 인데 ‘test’라는 4자짜리 문자열을 insert하게 되면 남는 공간은 6개의 공백으로 채우게 된다.
따라서 무조건 처음 선언된 10byte가 소요된다. -
값을 받아 올 때 이 공백은 자동으로 제거되며 PAD_CHAR_TO_FULL_LENGTH 모드를 활성화하면 공백까지 다 읽어온다.
-
삽입되는 데이터가 선언된 길이보다 작다면 남는 공간은 스페이스로 채워지므로 공간의 낭비가 발생하여
고정길이에 해당하는 데이터만 CHAR로 선언하는 것이 좋다.
2. VARCHAR 형
-
VARCHAR는 이름이 의미하듯 가변길이이다.
-
데이터를 삽입하면 데이터값외에 삽입된 문자열의 길이를 저장하는데
255글자 이하에는 1바이트, 그 이상은 2바이트의 추가 공간을 필요로 한다. -
즉 실질적인 데이터와 길이 정보도 같이 저장된다.
-
예를 들어 VARCHAR(10)에 ‘test’라는 4자짜리 문자열을 삽입하면
4byte + 1byte(길이를 저장하기 위한 메모리) = 5byte가 소모된다. -
저정할 수 있는 길이는 0부터 255까지이며
MySQL 5.0.3 이후에는 0부터 65,535까지 지정할 수 있다. -
VARCHAR 값은 저장될 때에 공백이 추가되지 않고, 공백에 대한 처리는 버전에 따라 다르다.
-
MySQL 5.0.3 이후부터는 표준 SQL과의 호환성을 위해 뒤따르는 공백들을 제거하지 않고 보관하며 읽어들일 때도 보존해준다.
-
MySQL 5.0.3 이전에는 저장될 때에 뒤따르는 공백들은 제거되었고 이는 값을 읽어들일 때에도 제거된 채로 읽힘을 의미한다.
-
MySQL 5.0.3 이전에 뒤따르는 공백들을 유지하기 위해서는 BLOB나 TEXT 형을 선택해야 했다.
-
기존 데이터 길이보다 더 큰 데이터로 업데이트할 경우 데이터 파편화가 발생한다.
-
기존 보다 큰 데이터를 저장하기 위해서 새로운 저장 영역에 새로 할당해야하므로 데이터 파편화가 발생한다.
-
테이블 ROW 중에 CHAR, VARCHAR 타입이 섞여 있으면 데이터 파편화는 발생할 수 밖에 없다.
-
파편화를 염두하고 설계한다면 테이블의 데이터 타입 중에 VARCHAR 타입을 사용해선 안된다.
-
그러나 MySQL에서는 다음의 쿼리를 적용하면 파편화를 막을 수 있다.
ALTER TABLE tblname ROW_FORMAT = FIXED;
-
VARCHAR 타입을 CHAR 타입처럼 동작하도록 강제로 지정하는 것이다.
-
CHAR처럼 동작하기 때문에 데이터 용량은 증가하지만
-
VARCHAR로 인한 파편화로 성능 저하는 막을 수 있다.
-
특이한 점으로는 4자 이하의 VARCHAR는 CHAR로 자동 변환된다.
-
만약 테이블안에 VARCHAR나 text, blob 같은 가변길이 데이터가 하나라도 있을 경우
3자 이상의 CHAR컬럼이 자동으로 VARCHAR로 바뀌게 된다. -
TABLE을 만든 후 실제로 무슨 형으로 변환되었는지 DESC table_name으로 확인 할 수 있다.
-
이렇게 하는 이유는 물론 성능과 속도 때문이다.
Q. 그렇다면 모두 VARCHAR를 사용하지 않는 이유는 무엇일까?
- 무조건 VARCHAR를 사용시 가변이기 때문에
내부에서 추가적인 Logic이 발생되어 속도 저하를 일으킬 수 있다.
CHAR와 VARCHAR의 비교
저장 영역
-
CHAR형은 고정형. 최대 길이는 255.
-
VARCHAR형은 가변형. 최대 길이는 255,
MySQL 5.0.3 이후부터는 65,535까지 가능. -
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
"select * from variable"
"select * from fixed"
2개의 쿼리를 사용
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이 동작한다면 길이를 초과하는 값을 저장되지 않고 에러를 발생시키게 된다.