본문으로 건너뛰기

CHAR-VARCHAR

1. CHAR와 VARCHAR 타입​

  • CHAR와 VARCHAR는 MySQL에서 문자열 데이터를 저장하는 가장 기본적이고 중요한 데이터 타입입니다.
  • 두 타입은 문자열을 저장한다는 공통점이 있지만, 저장 방식, 검색 방식, 메모리 사용량, 성능 특성에서 중요한 차이점을 보입니다.

1.1 핵심 차이점​

  • 저장 방식: CHAR는 고정 길이, VARCHAR는 가변 길이
  • 공간 효율성: VARCHAR가 일반적으로 더 효율적
  • 성능: CHAR가 특정 상황에서 더 빠를 수 있음
  • 후행 공백 처리: 두 타입이 서로 다른 방식으로 처리

1.2 언제 사용하는가?​

  • CHAR: 고정 길이 데이터 (국가 코드, 상태 코드, 해시값 등)
  • VARCHAR: 가변 길이 텍스트 (이름, 제목, 설명 등)

2. 기본 특성​

2.1 선언 방식​

  • CHAR와 VARCHAR 타입은 저장하려는 문자의 최대 길이를 나타내는 숫자와 함께 선언됩니다.
  • 이 숫자는 문자 개수를 의미하며, 바이트 수가 아닙니다.
  • 한글과 같은 멀티바이트 문자의 경우, 하나의 문자가 여러 바이트를 차지할 수 있습니다.
-- 기본 선언 방식
CHAR(길이) -- 고정 길이
VARCHAR(길이) -- 최대 길이

-- 구체적인 예시
CHAR(30) -- 정확히 30자, 항상 30자 공간 사용
VARCHAR(30) -- 최대 30자, 실제 길이만큼 공간 사용
VARCHAR(255) -- 최대 255자, 1바이트 길이 접두어 사용
VARCHAR(1000) -- 최대 1000자, 2바이트 길이 접두어 사용

2.2 문자 집합과 길이의 관계​

  • 사용하는 문자 집합(character set)에 따라 실제 저장 공간이 달라집니다.
-- UTF8MB4 문자 집합에서의 예시
CREATE TABLE example (
latin_char CHAR(10) CHARACTER SET latin1, -- 최대 10바이트
utf8_char CHAR(10) CHARACTER SET utf8mb4, -- 최대 40바이트
latin_varchar VARCHAR(100) CHARACTER SET latin1, -- 최대 100바이트
utf8_varchar VARCHAR(100) CHARACTER SET utf8mb4 -- 최대 400바이트
);

2.3 길이 제한​

2.3.1 이론적 최대 길이​

  • CHAR: 0~255자까지 설정 가능
  • VARCHAR: 0~65,535자까지 설정 가능
  • 위는 어디까지나 이론적인 최대 길이입니다.
    • VARCHAR의 실제 최대 길이는 최대 행 크기(65,535바이트)와 사용되는 문자 집합에 따라 제한됩니다.
    • 모든 컬럼이 이 제한을 공유합니다.

2.3.2 실제 제한 사항​

CREATE TABLE varchar_limit_test (
-- 이론적으로는 65,535자까지 가능하지만...
content VARCHAR(16383) CHARACTER SET utf8mb4 -- 실제 최대값
);
  • 위는 UTF8MB4 문자 집합에서의 실제 제한을 보여주는 예시입니다.
  • MySQL의 최대 행 크기: 65,535바이트
  • UTF8MB4의 한 문자당 최대 바이트: 4바이트
  • 길이 접두어: 2바이트 (255자 초과 시)
  • 따라서 실제 최대 길이는 아래와 같이 계산됩니다.
    • (65,535 - 2) / 4 = 16,383
  • 실제 최대 길이는 16,383자입니다.

2.3.3 다중 컬럼이 있는 경우​

-- 여러 VARCHAR 컬럼이 있을 때의 제한
CREATE TABLE multiple_varchar (
col1 VARCHAR(10000) CHARACTER SET utf8mb4, -- 40,000바이트
col2 VARCHAR(6000) CHARACTER SET utf8mb4, -- 24,000바이트
col3 VARCHAR(400) CHARACTER SET utf8mb4 -- 1,600바이트
-- 총합: 65,600바이트 > 65,535바이트→ 오류 발생!
);
  • 위는 여러 VARCHAR 컬럼이 있을 때의 제한을 보여주는 예시입니다.
  • 최대 행 크기(65,535바이트)를 초과하므로 오류가 발생합니다.

3. 저장 방식의 차이​

3.1 CHAR 타입의 저장 메커니즘​

  • CHAR 타입은 고정 길이 저장 방식을 사용합니다.

3.1.1 저장 과정​

-- CHAR(10) 컬럼에 다양한 값 저장
CREATE TABLE char_example (name CHAR(10));

INSERT INTO char_example VALUES
('A'), -- 'A ' (9개 공백 추가)
('ABC'), -- 'ABC ' (7개 공백 추가)
('ABCDEFGHIJ'); -- 'ABCDEFGHIJ' (공백 추가 없음)
  • 고정 길이: 선언된 길이로 고정 (항상 동일한 공간 사용)
  • 저장 시: 지정된 길이에 맞춰 우측에 공백으로 패딩
  • 검색 시: 기본적으로 후행 공백 제거 (PAD_CHAR_TO_FULL_LENGTH SQL 모드가 활성화된 경우 제외)

3.2 VARCHAR 타입의 저장 메커니즘​

  • VARCHAR 타입은 가변 길이 저장 방식을 사용합니다.

3.2.1 저장 과정​

-- VARCHAR(10) 컬럼에 다양한 값 저장
CREATE TABLE varchar_example (name VARCHAR(10));

INSERT INTO varchar_example VALUES
('A'), -- 길이 접두어(1) + 'A' = 2바이트
('ABC'), -- 길이 접두어(1) + 'ABC' = 4바이트
('ABCDEFGHIJ'); -- 길이 접두어(1) + 'ABCDEFGHIJ' = 11바이트
  • 가변 길이: 실제 데이터 길이에 따라 저장 공간 결정
  • 저장 방식: 길이 접두어 + 실제 데이터
  • 공백 처리: 저장 시 패딩하지 않음, 후행 공백 유지

3.2.2 길이 접두어 시스템​

  • VARCHAR는 데이터 앞에 길이 정보를 저장합니다
  • 255바이트 이하: 1바이트 길이 접두어 사용 (0~255 표현)
  • 255바이트 초과: 2바이트 길이 접두어 사용 (0~65,535 표현)
-- 길이 접두어 예시
VARCHAR(100) -- 최대 100자, 1바이트 접두어 사용
VARCHAR(1000) -- 최대 1000자, 2바이트 접두어 사용

4. 저장 공간 비교​

4.1 기본 비교 (단일 바이트 문자 집합)​

  • 다음 표는 CHAR(4)와 VARCHAR(4) 컬럼에 다양한 문자열 값을 저장했을 때의 결과를 보여줍니다
  • latin1 등 단일 바이트 문자 집합 기준입니다.
값CHAR(4)저장 공간VARCHAR(4)저장 공간공간 효율성
''' '4바이트''1바이트VARCHAR가 75% 절약
'ab''ab '4바이트'ab'3바이트VARCHAR가 25% 절약
'abcd''abcd'4바이트'abcd'5바이트CHAR가 20% 절약
'abcdefgh''abcd'4바이트'abcd'5바이트CHAR가 20% 절약
문자열 잘림

마지막 행의 결과는 strict SQL 모드가 비활성화된 경우에만 적용됩니다. strict 모드에서는 컬럼 길이를 초과하는 값이 저장되지 않고 오류가 발생합니다.

4.2 UTF8MB4 문자 집합에서의 비교​

한글을 포함한 UTF8MB4 환경에서의 저장 공간:

-- UTF8MB4 테스트 테이블
CREATE TABLE utf8_test (
char_col CHAR(10) CHARACTER SET utf8mb4,
varchar_col VARCHAR(10) CHARACTER SET utf8mb4
) CHARACTER SET utf8mb4;

INSERT INTO utf8_test VALUES
('안녕', '안녕'), -- 한글 2자
('Hello', 'Hello'), -- 영문 5자
('안녕하세요', '안녕하세요'); -- 한글 5자
값CHAR(10) 실제 저장저장 공간VARCHAR(10) 저장저장 공간
'안녕''안녕' + 34바이트 패딩40바이트'안녕'7바이트 (1+6)
'Hello''Hello' + 35바이트 패딩40바이트'Hello'6바이트 (1+5)
'안녕하세요''안녕하세요' + 25바이트 패딩40바이트'안녕하세요'16바이트 (1+15)

4.3 대용량 데이터에서의 비교​

-- 대용량 TEXT 데이터 비교
CREATE TABLE large_text_test (
description VARCHAR(1000),
fixed_code CHAR(10)
);

-- 실제 저장 공간 계산
-- description에 100자 저장시: 2바이트(길이) + 100바이트 = 102바이트
-- fixed_code에 5자 저장시: 10바이트 (5자 + 5자 패딩)

4.4 공간 효율성 분석​

4.4.1 VARCHAR가 유리한 경우​

  • 짧은 문자열이 많은 경우: 이름, 제목 등
  • 길이가 다양한 경우: 설명, 주소 등
  • 빈 값이 많은 경우: 선택적 필드

4.4.2 CHAR가 유리한 경우​

  • 고정 길이 데이터: 국가 코드(KR, US), 상태 코드
  • 길이가 거의 최대값에 근접: 해시값, UUID
  • 성능이 중요한 경우: 자주 조회되는 키 값

5. SQL 모드에 따른 처리​

5.1 비엄격 모드 (Non-strict Mode)​

strict SQL 모드가 비활성화된 경우:

  • CHAR 또는 VARCHAR 컬럼의 최대 길이를 초과하는 값이 할당되면, 값이 잘려서 저장됩니다
  • 경고 메시지가 생성됩니다
  • 공백이 아닌 문자가 잘릴 때도 경고만 발생하고 삽입은 진행됩니다

5.2 엄격 모드 (Strict Mode)​

strict SQL 모드가 활성화된 경우:

  • 공백이 아닌 문자가 잘릴 경우 오류가 발생합니다
  • 값 삽입이 거부됩니다
  • 길이 초과 시 데이터가 저장되지 않습니다

5.3 후행 공백 처리​

5.3.1 VARCHAR 컬럼​

  • SQL 모드와 관계없이 컬럼 길이를 초과하는 후행 공백은 삽입 전에 잘립니다
  • 경고가 생성됩니다

5.3.2 CHAR 컬럼​

  • SQL 모드와 관계없이 삽입된 값의 초과 후행 공백은 자동으로 잘립니다
  • 경고 없이 처리됩니다

6. 후행 공백 처리의 차이점​

6.1 저장 시 동작​

  • VARCHAR: 저장 시 패딩하지 않으며, 후행 공백이 유지됩니다
  • CHAR: 지정된 길이에 맞춰 우측에 공백으로 패딩됩니다

6.2 검색 시 동작​

  • VARCHAR: 저장된 후행 공백이 그대로 반환됩니다
  • CHAR: 후행 공백이 제거되어 반환됩니다 (PAD_CHAR_TO_FULL_LENGTH SQL 모드가 활성화된 경우 제외)

6.3 실제 예시​

-- 테이블 생성
CREATE TABLE vc (v VARCHAR(4), c CHAR(4));

-- 후행 공백이 있는 데이터 삽입
INSERT INTO vc VALUES ('ab ', 'ab ');

-- 결과 확인
SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;

결과:

+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab ) | (ab) |
+---------------------+---------------------+

VARCHAR는 후행 공백을 유지하지만, CHAR는 검색 시 후행 공백이 제거됩니다.

7. 콜레이션과 패딩 속성​

7.1 문자열 정렬과 비교​

  • CHAR, VARCHAR, TEXT 컬럼의 값들은 해당 컬럼에 할당된 문자 집합 콜레이션에 따라 정렬되고 비교됩니다.

7.2 PAD_ATTRIBUTE 속성​

  • MySQL의 모든 콜레이션은 PAD_ATTRIBUTE라는 속성을 가지며, 이 속성에는 두 가지 값이 있습니다:
  • PAD SPACE
    • 대상: 대부분의 콜레이션 (기본값)
    • 동작: 문자열 비교 시 후행 공백을 무시
    • 예시: 'hello' = 'hello ' → true (같다고 판단)
  • NO PAD
    • 대상: UCA 9.0.0 이상 기반 유니코드 콜레이션
    • 동작: 문자열 비교 시 후행 공백을 의미 있는 문자로 취급
    • 예시: 'hello' = 'hello ' → false (다르다고 판단)

7.3 PAD_ATTRIBUTE 속성 확인​

  • 콜레이션의 패드 속성을 확인하려면 INFORMATION_SCHEMA.COLLATIONS 테이블의 PAD_ATTRIBUTE 컬럼을 사용합니다.
-- 콜레이션의 PAD_ATTRIBUTE 속성 확인
SELECT COLLATION_NAME, PAD_ATTRIBUTE
FROM INFORMATION_SCHEMA.COLLATIONS
WHERE COLLATION_NAME = 'utf8mb4_general_ci';
SQL 모드의 영향

서버 SQL 모드는 후행 공백과 관련된 비교 동작에 영향을 주지 않습니다.

8. 특수 상황​

8.1 InnoDB의 대용량 CHAR 필드 최적화​

  • InnoDB는 768바이트 이상의 고정 길이 필드를 가변 길이 필드로 인코딩하여 오프페이지에 저장할 수 있습니다.
  • 예시:
    • utf8mb4 문자 집합에서 CHAR(255) 컬럼
    • 문자 집합의 최대 바이트 길이가 3보다 큰 경우 (utf8mb4는 4바이트)
    • 255 × 4바이트 = 1,020바이트로 768바이트를 초과
    • 이 경우 InnoDB가 내부적으로 최적화를 적용
InnoDB 최적화

대용량 CHAR 필드는 실제로는 가변 길이처럼 처리되어 성능과 공간 효율성이 개선됩니다.

8.2 인덱스와 중복 키 오류​

  • 후행 패드 문자가 제거되거나 비교에서 무시되는 경우 인덱스와 중복 키 오류가 발생합니다.
  • 유니크 인덱스가 있는 컬럼에서 후행 패드 문자 수만 다른 값을 삽입하면 중복 키 오류가 발생합니다
  • 예를 들어, 테이블에 'a'가 있을 때 'a ' (후행 공백 포함) 삽입 시 중복 키 오류가 발생합니다.

참고​