제가 개발을 하면서 DB에 가장 많이 사용하는 타입이 CHAR, VARCHAR 입니다.
그런데 CHAR와 VARCHAR의 공통점과 차이점에 대해서 정확하게 알지 못한 상태로
가변이면 VARCHAR, 고정이면 CHAR를 사용하면 된다! 정도로 이해하고 사용했습니다.
더 이상 이렇게 살면 안될거 같아 정리해야겠다는 마음이 들어서 포스팅을 작성하게 되었습니다.
CHAR의 VARCHAR 간단 소개
먼저 간단하게 공통점과 차이점에 대해서 정리해보겠습니다!
공통점
- 문자열 저장용 컬럼
- 최대 저장 가능 문자 길이 명시 가능! (byte 수가 아님!!)
CHAR(10)
,VARCHAR(10)
은 모두 10글자 까지 저장 가능
차이점
CHAR
는 값의 실제 크기에 관계없이 고정된 공간 할당VARCHAR
는 값의 실제 크기에 맞게 공간 할당- 최대 저장 길이
CHAR(255)
vsVARCHAR(16383)
→ (65535 bytes)
VARCHAR
는 저장된 값의 길이 관리하는 길이 저장 byte가 존재
CHAR
에서도UTF-8mb4
와 같이 가변 길이 문자셋을 사용하는 경우에는VARCHAR
와 같이 길이 저장 byte가 존재!
공통점과 차이점을 알아 보았으니 실제로 어떻게 저장되는지 알아봅시다!
디스크에 CHAR, VARCHAR는 어떻게 저장될까?!
Latin1 character-set 을 사용하는 경우(고정길이 문자 셋)
first_name CHAR(10)
이라는 컬럼에 ABCD 를 저장하게 되면, 10 bytes의 공간을 할당한 상태에서 4 bytes에 ABCD가 저장되고 6 bytes는 비워두는 방식을 사용합니다.
first_name VARCHAR(10)
이라는 컬럼에 ABCD 를 저장하게 되면, 4 bytes에만 ABCD가 저장되고 길이 저장 byte에 1바이트가 할당 됩니다.
문자 셋에 관계없이, 꼭 필요한 만큼만 공간을 사용합니다.
UTF8mb4 character-set 을 사용하는 경우(가변길이 문자 셋)
UTF8mb4 문자셋을 사용하는 경우 1글자는 최대 4 bytes를 사용할 수 있습니다.
따라서 CHAR (10) 컬럼은 최대 40 bytes 까지 빈 공백으로 예약할 수 있는 것처럼 보입니다.!!
하지만, 실제 MySQL 서버는 빈 공백 공간을 예약할 때는 문자의 갯수보다는 byte 수로 빈 공백 공간을 예약하도록 동작합니다.
따라서 first_name CHAR(10)
에 “한글” 이라는 2글자를 저장하면 한글 1글자는 3 bytes 씩 사용하기 때문에 총 6 bytes를 사용하게 됩니다.
그리고 byte 수 기준으로 공백 4개를 채우게 됩니다.
“한글연습” 이라는 4글자를 저장하면 12바이트를 사용하게 되고, 빈공간을 할당하지 않습니다.
어…? 왜 빈공간을 할당하지 않을까요?! 🤔
바로 CHAR(10) 컬럼 타입에 정의된 길이보다 더 큰 길이여서 추가로 빈 공간을 더 할당해 두지 않은 것 입니다!
first_name VARCHAR(10)
이라는 컬럼은 문자 셋에 관계없이, 꼭 필요한 만큼만 공간을 사용합니다.
저장되는 값의 길이 변동이 크지 않다면 CHAR
타입을 적용해보자!
일반적으로 고정된 길이의 값 저장은 CHAR
타입을 사용하고, 그외 경우에는 VARCHAR
타입을 사용해야한다?!
이 이야기는 틀린 말 입니다.!
VARCHAR
를 사용하면 좋은 경우는 바로 CHAR
타입의 공간낭비가 심할 경우에 사용하면 좋습니다.
- 문자열의 가변 폭이 큰 경우(1 ~ 100)
CHAR
를 사용하면 좋은 경우는 바로 CHAR
타입의 공간낭비가 심하지 않는 경우에 사용하면 좋습니다.
- 문자열의 가변 폭이 작은 경우(90 ~ 100)
저장되는 값의 길이 변동이 크지 않다면 CHAR 타입을 적용해보는 것이 좋습니다!
VARCHAR 컬럼 값의 길이 변경시 작동 방법
first_name VARCHAR(10)
컬럼에 ABCD를 ABCDE로 UPDATE를 하게 된다면, MySQL 서버는 레코드의 길이가 ABCD 4글자에서 ABCDE 5글자로 변경되었기 때문에 기존에 레코드가 저장되어 있던 위치에 inplace 로 저장할 수 없다는 것을 알게 됩니다.
따라서 새롭게 빈 공간에 레코드를 저장하게 됩니다.
만약에 해당 레코드가 자주 변경되고, 삭제되는 작업이 반복 된다면 계속 새로운 빈공간을 찾는 일이 많아질 것입니다!!
VARCHAR
대신 CHAR
를 사용한다면, 이러한 과정(새로운 빈공간을 찾는 작업)을 하지 않아도 됩니다!
따라서 문자열의 가변 길이 차이가 적고 자주 변경되는 컬럼인 경우에는 VARCHAR
대신에 CHAR
를 사용하면 컬럼의 길이 변경시에 데이터 페이지 관리 작업을 최소화 할 수 있습니다!
결국, 레코드의 이동이 줄어들고 fragmentation
이 줄어들면서 공간 절약 효과까지 얻을 수 있습니다!
정리
- 데이터 페이지 내부의 조각화(fragmentation) 현상 발생
- CHAR 타입 보다 공간 효율 떨어짐
- 내부적으로 빈번한 Page Reorganize 작업 필요
정리
VARCHAR 보다 CHAR 선택하는 경우
- 값의 가변길이 범위 폭이 좁다.
- 값이 자주 변경된다.(특히 인덱스된 컬럼인 경우)
참고
'데이터베이스 > 0 + MySQL' 카테고리의 다른 글
[MySQL] Stored Function 에서 많이 하는 실수 방지하기 (0) | 2024.08.21 |
---|---|
[MySQL] left join 아무생각 없이 사용하고 있는 것은 아니지? (0) | 2024.08.15 |
[MySQL] 페이징 쿼리 작성하기 (0) | 2024.07.21 |
[MySQL] count(*) 과 count(distinct) (2) | 2024.07.20 |
[MySQL] VARCHAR vs TEXT (1) | 2024.07.20 |