기맹기 개발 블로그

MySQL의 문자열, VARCHAR와 TEXT 이야기 본문

DB

MySQL의 문자열, VARCHAR와 TEXT 이야기

기맹기 2023. 3. 13. 04:47

테이블을 설계할 때 큰 길이의 문자열이 들어갈 것으로 예상되는 컬럼에는 TEXT 타입을 선언해본 경험이 있다. 그렇다면 VARCHAR 와 TEXT 는 무엇이 다르며, 각 타입은 어떤 경우에 설정하는 것이 적절한지 알아보도록 하자.

 

1. 문자열 타입들

VARCHAR와 TEXT를 비교하기 앞서서 문자열 타입들의 종류와 특징들을 살펴보자.

 

1-1. CHAR , VARCHAR

CHAR은 고정 길이 문자열으로, 테이블 정의에 선언된 길이로 고정된다.

따라서 남은 공간은 공백으로 채워진다.

그렇다면 다음의 경우 조회 쿼리의 결과는 어떻게 될까?

CREATE TABLE my_test (name CHAR(10));

INSERT INTO my_test VALUES ('hello');

SELECT name = 'hello', name = 'hello     ' FROM my_test;

남은 5글자의 공간이 공백으로 채워지므로 두번째 ‘hello ‘만 조회될 것이라 생각할 수 있다.

하지만 CHAR 타입의 특성을 고려하여 MySQL에서는 두 경우다 조회에 성공한다.

 

단 LIKE 연산자에 대해서는 이와 같이 동작하지 않으므로 주의해야 한다. (LIKE ‘hello’ 만 조회에 성공한다)

 

VARCHAR는 가변 길이 문자열로, 길이 정보를 위한 추가 공간을 1 ~ 2 바이트정도 차지한다. (레코드의 크기가 255바이트를 넘는지에 따라 결정된다.) 대신 CHAR처럼 공백을 채우지 않고 필요한 공간만큼만 차지한다.

 

1-2. BINARY , VARBINARY

기본적으로 CHAR, VARCHAR와 비슷하지만 문자열이 아닌 바이트로 저장되는 차이점이 있다.

다만 CHAR와 BINARY는 모두 남는 공간을 공백으로 채우지만 차이점이 있다.

BINARY는 남는 공간을 ‘\0’ 문자로 채워넣으며, equal 연산에 대해서 완벽하게 일치할 때에만 true를 반환한다.

아래의 예시를 보자.

CREATE TABLE my_table (bin_col BINARY(3));

INSERT INTO my_table VALUES ('a');

SELECT bin_col = 'a', bin_col = 'a\\0\\0' from my_table;

앞의 = ‘a’에 대해서는 공백 바이트 문자가 일치하지 않아서 false를, = ‘a\0\0’만 true를 반환하게 된다.

 

1-3. BLOB , TEXT

BLOB과 TEXT는 대량의 텍스트를 저장할 때 이용되며, 크기에 따라 타입이 더 분류된다.

단순히 크기 외에도 VARBINARY, VARCHAR와의 차이점이 존재한다.

  • 인덱싱
    • 인덱스로 지정하려면 index prefix length 를 반드시 설정해야한다. (VARBINARY, VARCHAR는 선택사항이다.)
  • 디폴트 값
    • BLOB, TEXT는 디폴트 값을 가질 수 없다.
  • 최대 길이
    • 최대길이는 항상 고정적이다.

이외에도 다음과 같은 주의사항이 존재한다.

  • 크기가 매우 클 수 있으므로, max_sort_length 만큼만 정렬에 이용된다. (기본값은 1024)
  • 임시 테이블을 사용한 쿼리에 BLOB, TEXT 타입의 열이 포함되면 메모리 엔진에서 처리할 수 없다. 따라서 디스크를 사용하며 이는 성능 저하를 발생시킬 수 있다.
  • 클라이언트와 서버 각각 메모리 가용량과 통신 버퍼 크기를 고려하여 max_allowed_packet 을 설정할 수 있다.

 

이외에도 문자열 타입에는 ENUM, SET 이 있지만 이번 주제와 관련성이 적어서 다음에 다뤄보도록 하겠다.

 

2. 사용하는 저장용량

가변길이 타입의 경우 저장된 문자열의 실제 길이 L 에 비례하는 공간을 차지한다.

 

문자열 타입 차지 용량
CHAR(M) (character set에 속한 문자의 최대 길이 w)
M * w 바이트, M ≤ 255
BINARY(M) M 바이트, M ≤ 255
VARCHAR(M), VARBINARY(M) L + 1 바이트 (0 ~ 255바이트)
L + 2 바이트 (256바이트 ~ 2^16 - 1바이트)
TINYBLOB, TINYTEXT L + 1 바이트, L < 2^8
BLOB, TEXT L + 2 바이트, L < 2^16
MEDIUMBLOB, MEDIUMTEXT L + 3 바이트, L < 2^24
LONGBLOB, LONGTEXT L + 4바이트, L < 2^32

 

3. 결론

3-1. 문자열 길이가 긴 경우

VARCHAR는 최대 65535자를 지원하므로, 이를 초과하는 데이터가 예상되면 MEDIUMTEXT, LONGTEXT 등을 이용할 수 있다.

 

3-2. 인덱싱이 필요한 경우

VARCHAR는 B-tree 인덱스로 사용할 수 있고, TEXT는 검색 목적의 full text를 사용해야 한다.

이를 고려하여 인덱싱이 필요한 경우 VARCHAR를 선택하는 것이 좋다.

 

3-2. 문자열이 길지 않은 경우

TEXT와 VARCHAR 모두 최대 65535자를 지원한다.

그렇다면 앞서 설명대로 성능 상 이슈가 발생할 수 있는 TEXT보다 VARCHAR를 쓰는 것이 항상 좋지 않은가라는 생각이 든다.

 

하지만 VARCHAR의 최대 길이는 필드 단위가 아닌, 레코드 단위이다.

즉 특정 필드가 너무 큰 용량을 차지하면, 나머지 필드가 사용할 공간이 줄어든다.

예를 들어 아래와 같은 테이블을 보자.

 

CREATE TABLE my_post (title VARCHAR(100), content VARCHAR(50000), meta VARCHAR(20000));

조금 억지스럽게 필드를 설정하긴 했지만, 위의 경우 하나의 레코드에서 최대 7만 바이트 이상의 VARCHAR를 저장하려고 하기 때문에 가득 찬 레코드는 문제가 생길 수 있다.

따라서 이론상 최대 크기인 65535에 근접하여 사용할 수 있거나, 큰 VARCHAR를 여러 개 사용하는 경우에는 TEXT로 선언하는 것이 좋다.

 

이러한 경우가 아니며, 적절하게 사용한다면 TEXT보다 VARCHAR를 사용하는 것이 저장용량이나 성능 면에서 이점이 있을 수 있다.


참조