VARCHAR vs TEXT (이래서 JPA와 함께 SQL Mapper를!?)

저뉼(스님?)·2023년 6월 19일
3

나만의 설명

목록 보기
10/11

⭐️ 당근마켓 - VARCHAR vs TEXT ⭐️ 를 참고하여 두 타입의 차이점에 대한 오류 수정.

(MySQL 8.0.32, Workbench 8.0 기준)

VARCHAR

CREATE TABLE `product` (
    `id` BIGINT NOT NULL,
    `product_name` VARCHAR(50) NOT NULL, // 요놈
    PRIMARY KEY (`id`)
);

괄호 안의 숫자의 정체

product_name VARCHAR(5)

  • 괄호 안의 숫자는 문자 최대 개수 (컬럼 만들 때 명시해야 함)
    • '123'
    • '12345'
    • 'abcde'
    • '일이삼사오'

5개를 초과하는 문자를 넣으려고 하면?

  • '123456'
  • 'abcdef'
  • '일이삼사오륙'

Error Code: 1406. Data too long for column 'product_name' at row 1

실제 크기

  • UTF8 기준, 영어 1 바이트, 한글 3 바이트. (이모티콘 4 바이트)
    • '123': 3 바이트 (= 1 바이트 x 3)
    • '12345': 5 바이트 (= 1 바이트 x 5)
    • 'abcde': 5 바이트 (= 1 바이트 x 5)
    • '일이삼사오': 15 바이트 (= 3 바이트 x 5)

즉, 타입이 같은 VARCHAR(5)라도 실제 사이즈는 다를 수 있음.
그래서 "가변길이"라는 말을 씀. (고정은 CHAR)

최대 크기

Q. 문자 개수는 얼마까지 설정할 수 있을까?
A. 일단은, 최대 16383까지 가능하다고 한다. VARCHAR(16383)

초과하는 숫자를 설정하려 하면 아래와 같은 에러 메시지를 확인할 수 있다.

ERROR 1074: Column length too big for column 'product_name' (max = 16383); use BLOB or TEXT instead

하지만 maximum row size limit이 존재하기 때문에 다른 컬럼들이 존재한다면 실제로는 최대 문자 개수가 더 줄어든다.

The MySQL maximum row size limit of 65,535 bytes is demonstrated in the following InnoDB and MyISAM examples.
- MySQL :: MySQL 8.0 Reference Manual :: 8.4.7 Limits on Table Column Count and Row Size

ERROR 1118: 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

TEXT

TINYTEXT, MEDIUMTEXT, LONGTEXT도 있음

  • 최대 65535 바이트의 문자열 저장
  • index 생성 불가
  • 테이블과 다른 곳에 저장됨

    Off-Page 라고 하는 외부 공간에 저장
    vs B-Tree (Clustering Index)에 저장(Inline 저장)

❗️길이가 길어서 저장 공간이 많이 필요한 경우에만
❗️근데 사실 VARCHAR도 길이가 너무 길어지면 다른 곳에 저장된대
-> 추가적인 작업 필요
-> 성능 떨어질 수 있음

*조회했을 때는 테이블의 다른 컬럼들과 같은 레코드에 있는 것처럼 보이지만 사실은 같은 레코드에 저장되지 않는다는 뜻.

  • Off-Page 저장소로 분리 저장되는 크기가 있는데, 그 크기만 넘지 않으면 TEXTVARCHAR든 둘 다 Inline 저장되고 또한 index(B-Tree 인덱스뿐만 아니라 전문 검색 인덱스까지)를 생성할 수 있다고 합니다.

오개념 정리

  • VARCHAR는 Inline 저장되고 TEXT는 Off-Page 저장소에 분리 저장된다.
  • VARCHAR는 index를 생성할 수 있고, TEXT는 index를 생성할 수 없다.

🤯 아니 그럼 도대체 언제 뭘 써야 해?

결정적인 차이

둘의 차이를 알려면 더욱 깊이 내려가야 하더라고.

MySQL엔진과 스토리지 엔진(예: InnoDB) 각각의 역할에 대해 알아야 하고,
MySQL엔진과 스토리지 엔진 사이에 데이터를 주고 받는다는 걸 알아야 하며
그때, 포인터가 활약한다는 걸 알아야 하더라고.

그리고 바로 여기서 차이점이 드러나는데,
VARCHAR는 최대 크기가 VARCHAR(100) 이런 식으로 설정되니까 기본적으로 미리 최대 크기로 메모리를 할당해 두고 재사용하는 반면,
TEXTBLOB 등의 LOB 타입 컬럼들은 그런 식으로 하면 메모리 낭비가 심해져서 레코드를 읽고 쓸 때마다 매번 메모리를 새로 할당 및 해제한다는 것이야.
단, VARCHAR도 길어지면 Off-Page 저장소로 분리 저장된다고 했지? 그럼 그때부터 똑같아지는 거야.

둘 다 장단점이 있어.
미리 할당된 메모리를 재사용하면 성능상 이점이 있겠지만 아무래도 메모리 공간을 계속 차지하고 있는 부담이 있겠고,
매번 메모리를 새로 할당하고 해제하는 건 성능상 문제가 될 수 있겠지만 메모리 공간을 효율적으로 사용할 수 있겠지.

결론

- index가 필요하고 사이즈가 적당한 범위 안인가? VARCHAR
- 그 외 게시판 글 내용이나 댓글 내용, 상품 상세 설명, 이메일 본문 등은 TEXT

기본적으로는 VARCHAR를 쓰되 특수한 경우에 TEXT 등을 쓰는 게 맞는 것 같은데,
언제 뭘 쓸지 판단하기 위한 기준을 다음과 같이 정리할 수 있을 것 같아.

  • 자주 접근하는(읽거나 쓰는) 컬럼일 때
    • 이때가 바로 VARCHAR의 장점이 발휘되는 순간이 아닐까?

그런데 아래의 경우들은 일부 VARCHARTEXT로 바꿔 줄 필요가 있을 것 같아.

  • VARCHAR 길이가 분리 저장될 정도로 큰가?
    • 분리 저장되면 VARCHARTEXT처럼 메모리 재할당 방식으로 돈다고 해.
      그럼 굳이 VARCHAR의 단점들을 감수하면서 써야 할까 싶네?
  • 분리 저장되진 않지만 길이가 긴 편인 VARCHAR들이 적지 않게 필요할 때
    • 최대 행 길이를 초과할 위험이 있으니까.
  • DMBS 서버의 메모리가 부족할 때
    • 성능을 좀 양보하더라도 메모리 효율을 높여야겠지.

깨달음

아, 그래서 JPA를 쓰고 있어도, 조회 모델은 따로 SQL Mapper를 이용하기도 하는구나.
데이터가 많고 트래픽이 높을 때, SQL Mapper로 필요하지 않은 TEXT 컬럼은 굳이 읽지 않으면 성능상 이점이 클 것 같네.

0개의 댓글