개요
MySQL 서버를 포함한 RDBMS를 사용하다 보면, No-SQL DBMS 서버에 비해서 많은 데이터 타입들을 가지고 있다. 하지만 RDBMS를 사용하면서 이런 다양한 데이터 타입에 대해서 정확한 용도와 특성을 모르면 RDBMS 서버가 어렵게 구현하고 있는 장점을 놓쳐 버릴 가능성이 높게 된다.
많은 개발자와 DBA들이 잘 모르고 있는 MySQL 서버의 VARCHAR 와 TEXT 타입의 특성과 작동 방식에 대해 요약을 해보았다.
VARCHAR 타입 궁금증
만약 10 글자 이하로만 저장된다면 컬럼의 타입을 VARCHAR(10)으로 하거나 VARCHAR(1000)으로 해도 아무런 차이가 없는 것 아닐까?
오히려 VARCHAR(1000)으로 만들어 두면 나중에 더 큰 값을 저장해야 할 때 더 유연하게 대응할 수 있지 않을까 ?
MySQL 서버가 내부적으로 어떻게 작동하는지를 모르면, 이 질문에 명확한 답변을 하기는 어려울 수 있다.-- 1. mysql> CREATE TABLE tb_long_varchar (id INT PRIMARY KEY, fd1 VARCHAR(1000000)); ERROR 1074 (42000): Column length too big for column 'fd1' (max = 16383); use BLOB or TEXT instead -- 2. mysql> CREATE TABLE tb_long_varchar (id INT PRIMARY KEY, fd1 VARCHAR(16383)); ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs -- 3. mysql> CREATE TABLE tb_long_varchar (id INT PRIMARY KEY, fd VARCHAR(16382)); Query OK, 0 rows affected (0.19 sec) -- 4. mysql> ALTER TABLE tb_long_varchar ADD fd2 VARCHAR(10); ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
tb_long_varchar테이블은 하나의VARCHAR컬럼이 있는데,VARCHAR타입의 최대 저장 가능 길이를 어느 정도로 하느냐에 따라서 테이블을 생성하지 못하게 되는 것을 확인할 수 있다.
그리고 네번째ALTER TABLE문장의 실행 예제를 보면, 새로운 컬럼 추가가 실패한 것을 알 수 있다. 이는 (에러 메시지에서도 잘 설명하고 있듯이) 이미tb_long_varchar테이블은 하나의 레코드가 저장할 수 있는 최대 길이가 65,535 바이트를 초과했기 때문에 더이상 새로운 컬럼을 추가할 수 없게 된 것이다.
이 예제를 통해서 MySQL 서버에서는 하나의VARCHAR컬럼이 너무 큰 길이를 사용하면, 다른 컬럼들이 사용할 수 있는 최대 공간의 크기가 영향을 받게 된다는 것을 확인할 수 있다. 그래서 MySQL 서버에서는 레코드 사이즈 한계로 인해서, VARCHAR 타입의 최대 저장 길이 설정시에 공간을 아껴서 설정해야 한다.
그런데VARCHAR타입의 길이 설정에 주의해야 하는 이유가 이거 하나 뿐일까? 예를 들어서 추가로 새로운 컬럼이 필요치 않아서 아래와 같이 테이블을 모델링했다면, 이건 아무 문제가 없는 것일까 ?CREATE TABLE user ( id BIGINT NOT NULL, name VARCHAR(4000), phone_no VARCHAR(4000), address VARCHAR(4000), email VARCHAR(4000), PRIMARY KEY(id) );
TEXT 타입 궁금증
그런데
VARCHAR대신TEXT타입을 사용하면 길이 제한 문제가 싹 사라진다는 것을 쉽게 확인할 수 있다.
그래서 아래와 같이 테이블을 만들면VARCHAR타입의 길이 설정에 대한 제약뿐만 아니라 저장하는 값의 길이 제한도 훨씬 크고 유연하게 테이블을 만들 수 있다.CREATE TABLE user ( id BIGINT NOT NULL, name TEXT, phone_no TEXT, address TEXT, email TEXT, PRIMARY KEY(id) );문자열 저장용 컬럼을 생성할 때,
VARCHAR와TEXT중에서 굳이VARCHAR를 선택할 이유가 있을까 ?TEXT타입은 저장 가능 길이도 훨씬 크고 테이블 생성할 때 굳이 길이 제한을 결정하지 않아도 되니 더 좋은 것 아닐까 ? 근데 왜 우리가 모델링하는 테이블에서 대부분 문자열 저장용 컬럼은TEXT컬럼이 아니라VARCHAR컬럼이 사용될까 ?
VARCHAR vs TEXT
RDBMS
TEXT같은 대용량 데이터를 저장하는 컬럼 타입을LOB(Large object)타입이라고 한다. 그리고 RDBMSLOB데이터를off-page라고 하는 외부 저장 공간에 저장을 한다.
MYSQL 서버도b-tree라고 하는 곳에 저장을 하지만 용량이 큰, 길이가 길어서 저장 공간이 많이 필요한 경우에만LOB데이터는 똑같이off-page에 저장을 하게 된다.
MYSQL 서버는uchar* records[2]라는 메모리 포인터를 이용해서 레코드 데이터를 주고 받는다. 이때 메모리 객체는 실제 레코드의 데이터 크기에 관계 없이 최대 크기로 메모리를 할당해준다.
varchar타입은 최대 크기가 설정되기 때문에 메모리 공간을records[2]버퍼에 미리 할당 받아둘 수 있지만,text타입은 실제 최대 크기만큼 메모리를 할당해 두면 메모리 낭비가 너무 심해지는 문제가 발생한다.
그래서records[2]포인터가 가리키는 메모리 공간은varchar는 포함하지만text컬럼을 위한 공간은 포함하지 않게 된다.
즉,records[2]메모리 버퍼는 처음 한번 할당되면 많은 컨넥션들에 의해서 재사용될 수 있도록 설계가 되어있는 것이다.
하지만text를 위한 메모리 공간은records[2]에 미리 할당되어 있지 않기 때문에 매번 레코드를 읽고 쓸 때마다 필요한 만큼 메모리가 할당되어야 한다.
컬럼 타입 선정 규칙
- VARCHAR :
VARCHAR는 저장할 문자열의 최대 길이를 설정해야 하며, 해당 길이에 맞춰 메모리가 할당됨- 일반적으로
VARCHAR타입은 길이가 상대적으로 짧은 문자열을 저장할 때 적합하며, 해당 컬럼이 자주 조회되는 경우 유리- 그러나
VARCHAR의 길이가 매우 길어지면, MySQL은 이 데이터를B-Tree외부의 공간(Off-Page)에 저장하게 되어TEXT와 유사한 방식으로 동작할 수 있음
- TEXT :
TEXT타입은 문자열 데이터의 최대 길이를 설정하지 않고, 길이에 따라 메모리가 동적으로 할당됨.- 주로 길이가 긴 문자열이나 큰 데이터를 저장할 때 사용되며, 메모리 낭비를 줄일 수 있다.
- 그러나
TEXT컬럼은 매번 메모리를 할당하고 해제해야 하므로, 자주 조회되는 데이터라면 성능에 영향을 줄 수 있다.
- 사용 시점 :
VARCHAR는 상대적으로 짧은 문자열을 저장하거나 메모리가 충분할 때 유리
TEXT는 길이가 긴 문자열 데이터를 저장해야 하거나 메모리 절약이 필요할 때 적합