콘텐츠로 이동

VARCHAR 길이 프리픽스 — VARCHAR(255)의 진짜 이유

정의

MySQL InnoDB는 VARCHAR 컬럼 값을 디스크에 저장할 때 실제 문자열 앞에 그 길이를 나타내는 "길이 프리픽스(length prefix)"를 1바이트 또는 2바이트로 붙입니다. 이 프리픽스가 1바이트로 끝날 수 있는 경계가 255 (2⁸ - 1)였기 때문에 과거에 VARCHAR(255)가 "마법의 숫자"로 자리잡았습니다.

관습(255)은 Latin1 시대의 최적값. utf8mb4 시대에는 VARCHAR(63)이 정확한 경계.

1바이트 vs 2바이트 프리픽스

InnoDB 규칙 (단순화):

컬럼의 최대 바이트 수 길이 프리픽스
≤ 255 bytes 1 byte
> 255 bytes 2 bytes

여기서 핵심 — VARCHAR(N)N은 "문자 수"이지 "바이트 수"가 아닙니다. 한 글자가 몇 바이트를 차지하느냐는 문자셋이 결정합니다.

문자셋별 경계값

문자셋 1글자 최대 바이트 1바이트 프리픽스로 가능한 최대 VARCHAR(N)
Latin1 (ASCII 시대) 1 byte VARCHAR(255) (255 × 1 = 255) ✅
utf8 (3 byte) 3 byte VARCHAR(85) (85 × 3 = 255) ✅
utf8mb4 (현대 표준) 4 byte VARCHAR(63) (63 × 4 = 252)
utf8mb4 4 byte VARCHAR(64) (64 × 4 = 256) → 2바이트 프리픽스

utf8mb4에서 VARCHAR(64)VARCHAR(255)는 둘 다 2바이트 프리픽스입니다. 관습대로 잡으면 의도와 다른 결과가 나옵니다.

성능 영향 — 1바이트 차이가 왜 중요한가

① 저장 공간

프리픽스 1 byte → 2 byte = 행당 +1 byte
1억 건 × 1 byte = 100 MB

작아 보이지만 테이블 1개·컬럼 1개 기준. 한 테이블에 VARCHAR 컬럼이 5개면 500MB.

② 인덱스 효율 (더 중요)

B-Tree 인덱스 페이지에도 프리픽스가 포함됩니다:

  • 페이지당 들어갈 키 개수 ↓
  • 페이지 스플릿(page split) 빈도 ↑
  • → I/O ↑, 캐시 효율 ↓
  • → 인덱스 검색·삽입 쿼리 성능 저하

대용량 테이블에서는 저장 공간 낭비보다 인덱스 효율 저하가 체감상 더 큽니다.

DB 제품별 차이

DBMS 길이 저장 방식 255 경계가 있나?
MySQL InnoDB 1 or 2 byte length prefix ✅ 있음 (이 페이지 주제)
PostgreSQL varlena (가변길이 헤더) ❌ 없음. 255든 256이든 저장 비용 동일
SQL Server row offset + length 경계 다름
Oracle length byte (~2 byte 비트필드) 다른 규칙

PostgreSQL 사용자라면 이 최적화가 무의미합니다. MySQL/MariaDB만 해당됩니다.

실무 의사결정 가이드

VARCHAR 크기 결정 시 우선순위:

  1. 도메인 요구사항 우선 — 이메일은 RFC 5321상 최대 254자. 이름·주소·URL 등 실제 데이터의 자연스러운 상한.
  2. 문자셋 확인 — utf8mb4가 기본이라면 63 경계 인식.
  3. 도메인 상한 ≤ 63VARCHAR(63)로 1바이트 프리픽스 확보.
  4. 도메인 상한 > 63 → 실제 필요 크기 그대로 둡니다. 억지로 줄이지 않습니다 (데이터 잘림이 훨씬 큰 손해입니다).
  5. PostgreSQL이면 이 페이지 무시, 도메인 요구만 따릅니다.

흔한 컬럼 예시 (utf8mb4 기준)

컬럼 합리적 선택 이유
username VARCHAR(50) 도메인 상한 작고 < 63
email VARCHAR(254) 또는 VARCHAR(320) RFC 5321 따름. 63 경계 의미 없음
phone VARCHAR(20) 국제전화 포함 짧음
slug VARCHAR(63) URL slug, 63 경계 활용 ✅
title VARCHAR(200) 도메인이 우선
password_hash (bcrypt) CHAR(60) 고정 길이, VARCHAR 불필요

"본말전도" 주의

"데이터를 자르는 위험을 감수하면서까지 무조건 숫자를 맞추는 것은 본말전도."

VARCHAR(63)이 모든 답은 아닙니다. 이메일을 63자로 자르면 RFC 위반이고 실제 데이터 손실입니다.

빠른 점검: 우리 테이블은 1바이트인가 2바이트인가?

-- utf8mb4 기준 빠른 진단
SELECT
  TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH AS chars,
  CHARACTER_OCTET_LENGTH AS bytes,
  CASE WHEN CHARACTER_OCTET_LENGTH <= 255 THEN '1-byte prefix ✅'
       ELSE '2-byte prefix ⚠️' END AS prefix
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
  AND DATA_TYPE = 'varchar'
ORDER BY CHARACTER_OCTET_LENGTH DESC;

2바이트 프리픽스라고 다 줄여야 하는 건 아니다. 자주 사용되는 인덱스 컬럼이면서 도메인상 63 이하로도 충분한 경우에 우선 검토.

원본 출처

관련 페이지