CHAR vs VARCHAR vs TEXT

1. 들어가며

 

이상적으로 데이터베이스 스키마를 설계할 때에는

 

논리 모델링 (업무 전문가)

  • 업무 분석
  • 엔티티 & 속성 & 관계 도출
  • 정규화

물리 모델링 (DBMS 전문가)

  • DBMS 벤더 별 최적 컬럼 타입 선정
  • 접근 패턴 분석
  • 반 정규화
  • 인덱스 전략 수립

와 같은 구조로 이루어진다고 합니다. 하지만 소규모 프로젝트는 논리 모델링과 물리 모델링을 함께 하는 편이 많고, 회사 크기가 작은 경우 DBA가 따로 없는 경우도 있습니다. 저도 현재 직접 데이터베이스 스키마를 설계하고 그걸 물리 모델링에 mapping을 하면서 여러 선택지에 놓이게 되는 경우가 많은데요. 그러면서 MySQL 지식에 대해 한계를 느낀 적이 있습니다. 그래서 저번에 읽은 Real MySQL을 다시 펼치고, inflearn의 저자 강의를 찾아 들으면서 더 공부해보고자 합니다.

 

오늘 내용은 String과 관련된 column의 타입인 CHAR vs VARCHAR vs TEXT에 대해 알아보도록 하겠습니다.

 

2. CHAR vs VARCHAR

 

공통점과 차이점

  • 공통점
    • 문자열 저장용 컬럼입니다.
    • 최대 저장 가능 문자 길이에 대해 명시합니다.
주의: 이 길이는 바이트 수가 아닙니다. 따라서 어떤 문자열 set을 사용함에 따라 저장되는 최대 문자 길이가 다릅니다.. utf-8, latin 문자열 셋 등 각 다르다)
  • 차이점
    • 값의 실제 크기에 관계없이 고정된 공간 할당 여부를 하는지 안 하는지 (CHAR의 경우 고정된 공간을 할당하지만 VARCHAR는 실제 사용 공간만 할당)
    • 최대 저장 길이: CHAR(255) vs VARCHAR (16383) → 6553 바이트
    • 저장된 값의 길이 관리 여부 (VARCHAR와 가변 길이 문자셋을 사용하는 CHAR는 저장된 값 길이 관리)
      • 0~255 bytes, length-bytes: 1
      • 256~65535 bytes length-bytes : 2

저장 방식

실제 구조

위 그림을 보면 저장 방식에 대해 더 이해가 잘 될 것 같습니다.

char의 경우 10으로 선언하면 해당 공간을 미리 예약하고

varchar의 경우 해당 크기만큼만 사용한다. 다만 varchar은 실제 저장된 크기도 맨 앞에 함께 저장합니다.

 

그럼 UTF-8(mb4)에서 어떻게 저장되는지 살펴볼까요?

 

  • varchar: 문자셋 관계 없이, 꼭 필요한 만큼만 공간 사용합니다.
  • char: 예약하는 공간 크기 달라짐. utf-8은 가변길이 문자셋이므로 길이 저장용 바이트 사용합니다.

즉 가변길이 문자셋의 경우 char이 varchar과 유사하게 동작할 수 있으며, char이라고 하더라도 사용하는 크기를 따로 저장해야 합니다.

 

사용 기준

그렇다면 어떨 때 CHAR를 사용하고 어떨 때 VARCHAR를 사용해야 할까요?

 

  • 일반적으로 알고 있는 구분 기준: 고정된 길이의 값은 CHAR 타입, 그 외의 경우 VARCHAR 타입을 사용한다고 많이 알고 있습니다. 근데 주민번호를 저장한다고 해볼까요? 단 1byte 차이 (크기 저장 byte)인데 그게 과연 클까요? 선택 기준이라고 하기엔 너무 미약한 것 같습니다.
  • CHAR 대신 VARCHAR를 사용하면?
    • 어떤 경우에는 CHAR 타입의 공간 낭비가 심합니다. (저장되는 문자열의 최소, 최대 길이 가변 폭이 큰 경우)
    • 하지만 그렇지 않은 경우도 있습니다. (저장되는 문자열의 최소, 최대 길이 가변 폭이 작은 경우)
    • 저장되는 값의 길이 변동이 크지 않다면 낭비는 크지 않습니다.

사용 기준을 정하기 위해선, 둘의 컬럼 값 길이 변경 시 작동 방법에 대해 알아야 합니다.

 

  • varchar의 경우:

처음 레코드 저장된 공간을 delete marking하고 새롭게 빈 공간에 record를 저장합니다. mysql은 row는 구조가 계속 바뀌고, 빈 공간을 찾기가 점점 어려워집니다. 그래서 페이지의 record를 compaction해야 되는 상황이 오게 됩니다.

  • char의 경우

처음엔 공간낭비처럼 남아있겠지만 예약된 공간이 있기 때문에 레코드를 통째로 옮겨 써야 하는 상황이 벌어지지 않습니다.

 

따라서 char vs varchar의 정확한 기준은 다음과 같습니다.

  • 저장되는 문자열이 자주 변경되는데 가변 길이가 크지 않다면 char을 사용하는 것이 좋습니다.
  • 왜냐하면 varchar의 경우 조각모음이 주기적으로 이루어지기 때문입니다.

 

3. VARCHAR vs TEXT

공통점과 차이점

  • 공통점
    • 문자열 속성 값을 저장
    • 최대 65,535 bytes 저장 가능
  • 차이점
    • VARCHAR 타입 컬림에는 지정된 글자 수 만큼만 데이터 저장 가능
      • VARCHAR(10) → 10글자 이하만 저장 가능
    • TEXT 타입 컬럼은 인덱스 생성 시 반드시 prefix 길이 지정 필요
      • CREATE INDEX ix_text_column ON table (text_column(100))
    • TEXT 타입 컬럼은 표현식으로만 디폴트 값 지정 가능
      • CREATE TABLE tb1 (col TEXT DEFAULT ‘abc’) → 에러 발생
      • CREATE TABLE tb1 (col1 TEXT DEFAULT (’abc’)) → 생성가능

사용 기준

일반적인 사용 형태는 다음과 같습니다.

  • 길이가 짧으면 VARCHAR 타입, 길이가 길면 TEXT 타입

그렇다면 VARCHAR(5000) vs TEXT는 어떤 차이가 있기에 위와 같은 사용 형태를 가지게 된 것일까요?

  • VARCHART 타입은 메모리 버퍼 공간을 미리 할당해두며 재활용 가능, TEXT 타입은 그때 그때 필요할 대마다 할당 & 해제

따라서 다음과 같은 사용 기준을 두는 것을 추천합니다.

  • 컬럼 사용이 빈번하고 메모리 용량이 충분하다면 VARCHAR 타입 추천합니다.
  • VARCHAR(5000)과 같이 길이가 긴 컬럼들을 자주 추가하는 경우, ROW 사이즈 제한 (65,535 byte)에 도달할 수 있으므로 적절하게 TEXT 타입과 같이 사용하는 것을 권장합니다.
  • VARCHAR(30) vs VARCHAR(255)?
    • 실제 최대 사용하는 길이만큼 명시해야 메모리 사용 효율이 증가힙니다. 이는 메모리에 버퍼 공간을 할당할 때 컬럼에 지정된 최대 길이만큼 할당하기 때문입니다. 따라서 실제 최대 사용하는 길이만큼만 할당하는 것이 효율적이다.
    • 디스크 공간 효율 차이도 미미하게 존재하는데 (1Bytes vs 2Bytes) → 전체 길이도 저장해야되기 때문입니다.

주의사항

저장되는 값의 사이즈가 크면 Off-Page 형태로 데이터가 저장될 수 있습니다.

Off-Page란? InnoDB는 하나의 레코드 크기가 데이터 페이지의 절반보다 큰 경우 외부 페이지에 저장하기 위한 column을 선택하게 되고 해당 외부 페이지를 가리키는 Pointer만 저장하게 됩니다. 그 외부 페이지를 OFF-page라고 합니다.

→ 따라서 쿼리에서 Off-page 컬럼의 참조 여부에 따라 쿼리 처리 성능이 매우 달라집니다.

해당 페이지에 대해서는 추가적인 column을 읽어야 하기 때문입니다.

쿼리 속도가 4배 가량 차이가 날 수 있으니 주의해야 합니다.

 

 

'Backend > DB' 카테고리의 다른 글

Stored Function  (0) 2024.12.26
COUNT(*) & COUNT(DISTINCT) 튜닝  (0) 2024.12.26
트랜잭션과 락  (2) 2024.03.07
MySQL 아키텍쳐  (0) 2024.03.06
쿼리 최적화  (0) 2024.03.06