0. Overview
MySQL의 문자열데이터 타입 중 자주 사용하는 VARCHAR와 이와 비슷한 TEXT 가 있죠 ? 기존의 VARCHAR는 255byte만 지원하다가 MySQL5.0.3 이후로 VARCHAR와 TEXT 타입 모두 최대 65,535byte 길이를 지원하게 되었습니다.
VARCHAR와 TEXT는 모두 문자열을 저장하기 위한 데이터 타입이며, 그렇다면 이 둘의 차이는 무엇일까? 라는 생각이 들었고 이를 알고자 글을 작성하게 되었습니다.
1. 저장 용량
VARCHAR의 저장 구조
VARCHAR는 최대 65,535byte까지 저장이 가능하며,
현재 저장된 byte의 크기 + 길이를 표현하는 byte로 구성됩니다.
- 255byte 이하의 데이터 저장 : 길이 접두사로 1byte를 사용하고 실제 문자열 데이터는 최대 65,534byte를 사용
- 255byte 초과하는 데이터 저장 : 길이 접두사로 2byte를 사용하며, 실제 문자열 데이터는 최대 65,532byte 사용
CREATE TABLE test_varchar(
id BIGINT NOT NULL,
name VARCHAR(4000),
phone_no VARCHAR(4000),
address VARCHAR(4000),
email VARCHAR(4000),
PRIMARY KEY(id)
);
→ VARCHAR로 선언된 필드들은 2바이트의 길이 접두사 + 4000바이트의 문자열로 구성됩니다.
[ VARCHAR 괄호안의 숫자의 정체 ! ]
예시를 들어보겠습니다. name VARCHAR(5) 라는 필드가 있을 때
괄호 안의 숫자는 문자의 최대 개수입니다.
- '123' 🙆🏻♂️
- '12345' 🙆🏻♂️
- 'pzero' 🙆🏻♂️
- '박영재영재' 🙆🏻♂️
하지만, 5개를 초과하는 문자를 넣으려고 하면 ?
- '123456' 🙅🏻♂️
- 'zerozae' 🙅🏻♂️
- '박영재입니다' 🙅🏻♂️
실제 크기를 살펴보면 또 다음과 같이 타입이 같은 VARCHAR(5)라도 실제 사이즈는 다를 수 있어요. (= 가변길이)
UTF8 기준 ( 영어 : 1byte, 한글 : 3byte )
- 'pzero' : 5바이트 (= 1 바이트 x 5)
- ' 박영재영재' : 15바이트 (= 3바이트 x 5)
TEXT의 저장 구조
TEXT도 최대 65,535바이트까지 저장할 수 있지만, VARCHAR와 달리 무조건 길이 접두사로 2바이트가 사용됩니다. 따라서 실제 문자열 데이터는 최대 65,533 바이트를 사용할 수 있습니다.
2. 저장 방식
MySQL 데이터베이스 관리 시스템의 스토리지 엔진 중 하나로 InnoDB 스토리지 엔진에서는 Inline과 Off-Page 스토리지가 존재하며 , InnoDB는 TEXT와 VARCHAR 타입의 데이터를 처리할 때, 그 데이터 길이가 특정 임계값을 넘지 않는다면 Inline 방식으로 데이터를 저장합니다.
- Inline 스토리지는 데이터가 레코드 내부에 직접 저장되며, 공간 사용 효율이 높아 짧은 문자열 저장에 효과적입니다.
- Off-Page 스토리지는 데이터가 레코드 외부, 별도의 공간에 저장되며 레코드 내부에는 해당 데이터 위치를 가리키는 포인터가 저장됩니다.
InnoDB 스토리지 엔진은 '페이지'라 불리는 블록 단위로 데이터를 저장하는데 일반적으로 이 페이지의 크기는 16KB입니다. 그러나 모든 16KB가 데이터 저장을 위해 사용되는 것은 아니고 페이지의 일부는 헤더, 트랜잭션 정보, 디렉토리 등의 시스템 정보에 사용되기 때문에 실제 레코드가 저장될 수 있는 공간은 페이지 크기의 절반 즉, 8,117바이트가 데이터 저장에 사용될 수 있어요.
결론적으로 8,117바이트를 초과하면 Off-Page로 저장하게 됩니다.
3. 인덱싱
VARCHAR는 전체 문자열에 대한 인덱스를 생성할 수 있어요. 정확히는 특정 길이 내에서는 전체 문자열에 대해 인덱스를 생성할 수 있습니다. InnoDB 스토리지 엔진을 활용하는 MySQL에서는 인덱스 항목의 최대 크기가 767 바이트로 제한되어 있어요.
일반적으로 사용하는 UTF-8 문자셋을 사용하면 한 문자당 최대 3바이트가 할당되기 때문에 255자(255 x 3 = 765) 까지의 인덱스를 생성할 수 있습니다.
반면에 TEXT 데이터 타입은 기본적으로 전체 문자열을 기준으로 인덱스를 생성할 수 없고, 반드시 일정 길이를 명시적으로 지정하여야만 인덱스를 생성할 수 있습니다.
CREATE INDEX idx_column_name ON table_name(column_name(100));
여기서 100은 TEXT 컬럼의 처음 100자를 인덱스로 사용하겠다는 의미입니다. TEXT 타입의 컬럼에 인덱스를 추가할 때 인덱스로 사용될 문자열의 길이를 지정하지 않으면 오류가 발생해요.
4. 메모리 관리
MySQL 서버는 데이터를 주고 받을 때 이전에 언급했던 스토리지 엔진인 InnoDB와 records[2]라는 배열 내의 두 메모리 포인터를 사용하여 레코드 데이터를 주고 받습니다.
records[2]는 MySQL의 핵심 구조 중 하나인 TABLE 구조체 내부에 위치하고, 이 배열은 두 개의 포인터로 이루어져 있습니다.
첫 번째 포인터는 현재 작업 중인 레코드를 가리키며, 두 번째 포인터는 직전에 처리된 레코드를 참조합니다.
데이터 타입에 따라 records[2]에서의 메모리 관리 방식이 달라집니다. VARCHAR와 같은 사전에 크기가 정의된 데이터 타입은 records[2]에 할당된 고정된 메모리 공간 내 데이터를 저장합니다. 반면 TEXT나 BLOB과 같은 크기가 가변적인 LOB 데이터 타입은 그 크기가 records[2]의 할당 범위를 초과할 수 있기 때문에 필요에 따라 동적으로 메모리를 할당받게 됩니다.
추가로 VARCHAR 역시 값이 매우 커 Off-Page 저장이 필요하게 되면, records[2]의 기존 메모리 영역을 사용할 수 없으므로 새로운 메모리 할당이 요구됩니다.
일반적으로는 VARCHAR는 records[2]에 할당된 고정된 메모리 공간 내 데이터를 저장해요.
5. 성능 확인의 어려움
LOB(Large Object) 데이터 타입은 큰 문자열 또는 바이너리 데이터를 저장하기 위해 사용됩니다. MySQL에서 이러한 타입에 해당하는 것은 TEXT와 BLOB입니다.
MySQL 8.0.33 버전까지는 Performance_schema에서 LOB 컬럼에 대한 메모리 할당 및 해제 정보를 측정하지 않았어요. 여기서 Performance_schema는 MySQL 서버의 다양한 내부 동작에 대한 성능 및 모니터링 정보를 제공하는 기능이에요. 따라서 데이터 베이스 성능을 모니터링하거나 분석할 때, 이러한 LOB 데이터에 대한 메모리 사용 패턴이나 관련된 성능 영향을 직접 확인할 수 없게 됩니다.
* 8.0.33 버전 이후에는 Performance_schema에서 LOB 컬럼에 대한 메모리 할당 및 해제 정보를 자동으로 추적하고 기록하는 방향으로 개선되었다고 해요.
🙋🏻♂️ 그럼, VARCHAR는 ?...
: Performance Schema는 다른 데이터 형식인 VARCHAR와 같은 컬럼의 대한 성능 정보를 모니터링하고 제공했어요. 예를 들어 VARCHAR 컬럼과 같은 문자열 형식은 성능 스키마의 다양한 테이블과 뷰에서 성능 정보를 제공하며, 문자열 길이, 할당된 메모리 , 쿼리 실행 시간 등과 관련된 정보를 포함할 수 있습니다.
그런데, 사실은 여기까지 살펴보아도 만약 VARCHAR(100) 이런식으로 설정되면 기본적으로 미리 최대 크기로 메모리를 할당해두고 재사용하는 반면, TEXT 같은 타입은 레코드를 읽고 쓸 때마다 매번 메모리를 새로 할당 및 해제하는데 VARCHAR도 길어지게 되면 Off-Page 저장소로 분리 저장된다고 했죠 ? 그럼 결국은 똑같아지는게 아닌가 ...
미리 할당된 메모리를 재사용하면 성능상 이점이 있겠지만 아무래도 메모리 공간을 계속 차지하고 있는 부담이 있을거고, 매번 메모리를 새로 할당하고 해제하는건 성능상 문제가 될 수 있지만 메모리 공간을 효율적으로 사용한다는 각각의 장단점이 존재하겠죠.. 그래서 도대체 언제 뭘 써야할까요 ?..
6. 정리
기본적으로 VARCHAR를 쓰되 특수한 경우 TEXT를 사용하는게 맞는거 같은데.. 언제 뭘 쓸지를 판단하기 위한 기준을 다음과 같이 정리할 수 있을 것 같습니다.
🔍 VARCHAR
- 해당 컬럼의 데이터가 테이블을 조회할 때마다 항상 필요할 경우 (자주 접근)
- DBMS 서버의 메모리가 (상대적으로) 충분한 경우
- 사용자 이름, 이메일 주소 , 제품 이름, 카테고리 등 고정적이진 않지만 짧은 문자열
🔍 TEXT
- VARCHAR 길이가 분리 저장될 정도로 클 때는 분리 저장되면 결국 VARCHAR도 TEXT처럼 메모리 재할당 방식으로 동작한다고 합니다. 그럼 굳이 VARCHAR의 단점들을 감수하며 사용할 필요가 없겠죠
- 테이블에서 긴 문자열 데이터를 저장해야 할 컬럼이 여러 개 필요한 경우
- 해당 컬럼의 데이터가 테이블을 조회할 때 마다 필요하지 않은 경우 (자주 접근 X)
- DBMS 서버의 메모리가 (상대적으로) 부족할 때
- 게시글 작성 내용, 코멘트, 리뷰 등 길이 예측이 어려운 문자열에 사용
< 참고 자료 >
MySQL에서 VARCHAR와 TEXT의 차이
개요 MySQL의 문자열데이터 타입 중 VARCHAR와 TEXT는 상당히 흔히 사용됩니다. 그동안 VARCHAR는 255byte만 지원했지만, MySQL 5.0.3 이후로 VARCHAR와 TEXT 타입 모두 최대 65,535byte 길이를 지원하게 되었습니다
dkswnkk.tistory.com
VARCHAR vs TEXT
개요
medium.com