*저장 방식과 최대 저장 크기에서 차이를 보임
*참고자료 : Medium#당근테크블로그(by sungluck Lee)
간단한 타입설명
1. CHAR
- 고정 길이 문자열 : 지정된 길이만큼 공간을 항상 할당, 10char = 10byte
- 빠른 검색 속도 : 고정길이로 인해 검색속도가 빠르다.
- 주로 짧은 문자열 저장에 사용 : 이름, 전화번호 등 길이가 비교적 짧고 일정한 데이터 저장에 적합
2. VARCHAR
- 가변 길이 문자열 : varchar는 저장되는 문자열의 길이에 따라 동적으로 공간을 할당
- 공간효율적 : 가변 길이로 인해 공간을 효율적으로 사용
- 다양한 문자열 저장 : 길이가 다양한 문자열 뎅터 저장에 적합
- 검색 속도 : char에 비해 검색 속도가 약간 느림
3. BLOB
- LOB타입
- Binary Large Object 는 이미지, 오디오, 비디오 등 바이너리 데이터를 저장하는데 사용
- 가변 길이 : 저장되는 데이터 크기에 따라 가변적으로 공간을 할당
- 대용량 데이터 저장 : 대용량 바이너리 데이터로 저장한다.
- 별도 저장 공간 : BLOB 데이터는 테이블 공간 외의 별도 저장 공간에 저장될 수 있다.
4. TEXT
- LOB타입
- 문자열 대형 객체 : text는 긴 문자열 데이터를 저장하는데 사용됩니다.
- 가변길이 : 저장되는 문자열의 길이에 따라 공간을 할당
- 대용량 텍스트 권장 : 긴 기사, 설명 등 텍스트 데이터를 저장
- BLOB과 유사한 저장방식 : BLOB과 유사하게 별도 저장 공간에 저장될 수 있다.
VARCHAR vs TEXT 비교
1. LOB과 Off-Page
- 일반적인 RDBMS에서 TEXT나 BLOB과 같은 대용량 데이터를 저장하는 컬럼 타입을 LOB(large object)라고 한다.
- LOB데이터는 off-page라고 하는 외부공간에 저장된다. 항상 그렇지는 않다.
2. LOB 저장위치
- 레코드의 컬럼데이터는 B-tree에 저장하고 (인라인저장), LOB데이터는 B-tree외부의 Off-Page로 저장(external off-page storage라고 함)
- 여기서 헷갈리는 점은 LOB타입 컬럼을 항상 Off-page에 저장하지는 않는다는 것이다.
- off-page에 저장되는 조건은 길이가 길 경우 저장공간이 많이 필요한 경우에만 저장한다는 것이다.
3. 용량에 따른 저장위치
- Inline인지 Off-Page인지를 결정하는 기준은 해당 테이터베이스 Page사이즈에 의해 좌우된다.
- B-tree(inline저장소)에 저장되는 것이 일반적이고 용량이 크면 off-page저장소에 저장한다.
- VARCHAR 컬럼에 저장된 값이 큰 경우에도 Off-Page로 저장된다
- VARCHAR 타입은 인덱스를 생성할 수 있는 반면, LOB 타입은 인덱스 생성을 할 수 없다는 이야기를 하는 사람도 있지만, 사실은 둘다 최대 크기 길이 제한만 충족시켜 주면 인덱스를 생성할 수 있다.
- B-Tree 인덱스뿐만 아니라 전문 검색 인덱스도 TEXT 타입과 VARCHAR 타입 컬럼 모두 동일하게 생성할 수 있다.
4. VARCHAR와 TEXT의 메모리 활용
-
MySQL 엔진과 InnoDB 스토리지 엔진은 uchar* records[2] 메모리 포인터를 이용해서 레코드 데이터를 주고 받는다.
-
이때 records[2] 메모리 객체는 실제 레코드의 데이터 크기에 관계 없이 최대 크기로 메모리를 할당한다.
-
VARCHAR 타입은 최대 크기가 설정되기 때문에 메모리 공간을 records[2] 버퍼에 미리 할당받아둘 수 있지만
-
TEXT나 BLOB와 같은 LOB 컬럼 데이터의 경우 실제 최대 크기만큼 메모리를 할당해 두면 메모리 낭비가 너무 심해서 records[2] 포인터가 가리키는 메모리 공간은 TEXT 컬럼을 위한 공간은 포함하지 않는다.
-
uchar* records[2] 메모리 공간은 TABLE 구조체(struct) 내에 정의되어 있으며 TABLE 구조체는 MySQL 서버 내부에 캐싱되어서 여러 컨넥션에서 공유해서 사용될 수 있도록 구현되어 있다.
-
records[2] 메모리 버퍼는 처음 한번 할당되면 많은 컨넥션들에 의해서 재사용될 수 있도록 설계
-
EXT나 BLOB과 같은 LOB 컬럼을 위한 메모리 공간은 records[2]에 미리 할됭되어 있지 않기 때문에 매번 레코드를 읽고 쓸 때마다 필요한 만큼 메모리가 할당되어야 해요
5. 버퍼 공간 할당 예시
CREATE TABLE tb_lob (
id INT PRIMARY KEY,
fd TEXT
);
CREATE TABLE tb_varchar1 (
id INT PRIMARY KEY,
fd VARCHAR(100)
);
CREATE TABLE tb_varchar2 (
id INT PRIMARY KEY,
fd VARCHAR(10000)
);
tb_lob 테이블을 위한 records[2] 버퍼 공간은 16 * 2 바이트만큼 할당
INT 타입의 컬럼(id)을 위한 4 바이트와 TEXT 값을 위한 포인터 공간 8바이트 그리고 헤더 공간 4바이트
tb_varchar1 테이블의 records[2] 버퍼 공간은 408 * 2 바이트를 할당
INT 타입의 컬럼(id)을 위한 4 바이트와 VARCHAR(100)타입 컬럼을 위한 공간 400바이트 그리고 헤더 공간 4바이트
tb_varchar2 테이블을 위해서는 records[2] 버퍼 공간은 40008 * 2 바이트를 할당
- INT 타입의 컬럼(id)을 위한 4 바이트와 VARCHAR(10000) 타입 컬럼을 위한 공간 40000바이트 그리고 헤더 공간 4바이트
6. VARCHAR과 TEXT의 선택 가이드
-
내부플로우에 대한 배경지식
- VARCHAR 타입의 컬럼을 읽을 때는 새롭게 메모리를 할당받는 것이 아니라 TABLE 구조체의 records[2] 버퍼를 이용
- TEXT나 BLOB와 같은 LOB 타입의 컬럼을 읽을 때는 (미리 할당해 둔 메모리 공간이 없기 때문에) 매번 필요한 크기만큼 메모리를 할당해서 사용후 해제
-
단점 :
- LOB용 메모리 할당 해제가 실행되는지 알 수 없어서 성능 영향도를 파악하기가 어렵다
-
주의사항 :
- VARCHAR 타입에 저장된 값의 길이가 길어서 Off-Page로 저장된 경우, MySQL 서버는 TABLE 객체의 records[2] 버퍼를 사용하지 못하고 새롭게 메모리 공간을 할당해서 사용
- 그래서 VARCHAR 타입에 매우 큰 값이 빈번하게 저장되는 경우는 주의가 필요하다.
-
결론
- B-Tree 인덱스뿐만 아니라 전문 검색 인덱스도
TEXT 타입과 VARCHAR 타입 컬럼 모두 동일하게 생성할수 있기때문에
- 보면 볼수록 TEXT와 VARCHAR의 차이가 명확해지기 보다는 오히려 모호하다
- 그렇다면 어떤 타입을 선정해야할까. 아래 글을 살펴보자.
컬럼 타입 선정 규칙과 요약
1. VARCHAR
- 최대 길이가 (상대적으로) 크지 않은 경우
- 테이블 데이터를 읽을 때(select) 항상 해당 컬럼이 필요한 경우
- DBMS 서버의 메모리가 (상대적으로) 충분한 경우
2. TEXT
- 최대 길이가 (상대적으로) 큰 경우
- 테이블에 길이가 긴 문자열 타입 컬럼이 많이 필요한 경우
- 테이블 데이터를 읽을 때 해당 컬럼이 자주 필요치 않은 경우
3. 정리
- 자주 읽는 컬럼 → VARCHAR
- 가끔 읽는 대용량 컬럼 → TEXT
- VARCHAR라도 값이 커지면 TEXT처럼 동작할 수 있으니, 데이터 특성에 따라 선택해야 함
4. 모호한 표현에 대한 해명
- 상대적이라는 단어가 많이 사용된 것은 DBMS 서버의 스펙이나 데이터 모델
그리고 유입되는 트래픽에 따라서 미치는 영향도가 다름
- 뿐만 아니라 DBMS 서버의 튜닝은 생산성(속도)과 효율성
사이에서 최적점(sweet-spot)을 찾는 과정이기 때문에 숫자 값 하나를 모든 판단의 기준으로 정하는 것은 불가능
- 그래서 상대적이다라고 표현한다.
가변/불변인지만 파악하기