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의 비교
저장 영역
-
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
-- 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이 동작한다면 길이를 초과하는 값을 저장되지 않고 에러를 발생시키게 된다.