MySQL VARCHAR 데이터 타입 심층 분석

VARCHAR(255)의 의미

VARCHAR(255)는 최대 255개의 문자를 저장할 수 있음을 의미합니다. 실제로 얼마나 많은 바이트를 차지하는지는 문자 집합(character set)에 따라 결정됩니다.

VARCHAR의 최대 길이는 얼마일까요?

이 질문을 검색해보면 65535라는 답변을 어느 정도 접했을 것입니다. 예를 들어, 현재 가장 인기 있는 인공지능에게 이 질문을 해보면 비슷한 답변을 얻을 수 있습니다.

하지만 VARCHAR의 최대 길이가 정말로 65535일까요? 직접 테스트해보겠습니다.

CREATE TABLE test_varchar_max (
    test_col VARCHAR(65535) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

MySQL은 오류 메시지를 표시하며, 최대값이 16383임을 알려줍니다. 이는 우리가 예상했던 것과 다릅니다. 그렇다면 VARCHAR의 최대 길이는 16383일까요? 계속 확인해보겠습니다.

CREATE TABLE test_varchar_max (
    test_col VARCHAR(65535) NOT NULL DEFAULT ''
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

이번에는 다른 오류 메시지가 표시됩니다. VARCHAR의 최대 길이는 대체 얼마일까요?

이 질문에 답하기 전에 몇 가지 개념을 이해해야 합니다.

문자 집합(Character Set)

주의 깊게 보셨다면 위 두 개의 CREATE TABLE 문장에서 charset 값만 다르다는 것을 발견했을 것입니다. charset은 테이블의 문자 집합을 설정합니다.

문자 집합이란 무엇일까요? 백과사전의 정의에 따르면:

문자(Character)는 각국의 문자와 기호의 총칭으로, 각국의 문자, 구두점, 그래픽 기호, 숫자 등을 포함합니다. 문자 집합(Character set)은 여러 문자의 모음으로, 종류가 다양하며 각 문자 집합이 포함하는 문자 수도 다릅니다. 주요 문자 집합 이름으로는 ASCII, GB2312, BIG5, GB18030, Unicode 등이 있습니다. 컴퓨터가 다양한 문자 집합의 텍스트를 정확하게 처리하려면 문자 인코딩을 수행해야 합니다. 이를 통해 컴퓨터는 다양한 문자를 인식하고 저장할 수 있습니다.

위의 실험을 통해 다른 문자 집합은 문자 인코딩 규칙이 다르기 때문에 저장 크기도 다르다는 것을 증명할 수 있습니다.

MySQL이 어떤 문자 집합을 지원하며, 각 문자 집합이 얼마의 공간을 차지하는지는 show charset 명령어로 확인할 수 있습니다.

그렇다면 이 최대 길이는 어떻게 계산할 수 있을까요? 이전에 문자 집합 오류가 VARCHAR의 최대 길이를 알려주었던 것을 기억하시나요? 해당 길이 × 문자 집합의 Maxlen이 VARCHAR의 최대값이 될까요? 위의 테스트 결과로 계산해보겠습니다.

  • utf8mb4의 Maxlen = 4 → VARCHAR 최대값 = 4 × 16383 = 65532
  • utf8의 Maxlen = 3 → VARCHAR 최대값 = 3 × 21845 = 65535

흠, utf8mb4와 utf8로 계산한 결과가 일치하지 않습니다. 다시 gbk 문자 집합으로 테스트해보겠습니다.

  • gbk의 Maxlen = 2 → VARCHAR 최대값 = 2 × 32767 = 65534

이제 완전히 일치하지 않습니다. 그렇다면 어떻게 해야 할까요? 사실 테스트해보셨다면 문제점을 발견했을 것입니다. utf8과 gbk은 오류 메시지에 최대값을 알려주었지만, 실제로 그 값을 설정하면 오류가 발생하며, 알려준 값보다 1 작은 값으로만 설정할 수 있습니다.

최근에 실제로 성공한 최대값으로 다시 VARCHAR의 최대값을 계산해보겠습니다.

  • utf8mb4의 Maxlen = 4 → VARCHAR 최대값 = 4 × 16383 = 65532
  • utf8의 Maxlen = 3 → VARCHAR 최대값 = 3 × 21844 = 65532
  • gbk의 Maxlen = 2 → VARCHAR 최대값 = 2 × 32766 = 65532

그렇다면 VARCHAR의 최대값이 65532바이트라고 생각하시나요? 정답부터 말씀드리면, 그건 틀렸습니다!!!

NULL 또는 NOT NULL?

위의 테스트는 VARCHAR가 65532바이트의 데이터를 저장할 수 있다는 것을 거의 증명했습니다. 하지만 모든 문자 집합의 Maxlen이 1보다 큰 것을 발견하셨나요? 65532가 이 문자 집합들의 Maxlen의 정수배일 가능성은 없을까요?

이 문제를 검증하는 것은 사실 매우 간단합니다. Maxlen이 1인 문자 집합을 하나 찾아 테스트해보면 됩니다.

latin 문자 집합의 VARCHAR는 65533으로 설정할 수 있으며, 이는 VARCHAR의 최대 바이트가 65533 × 1 = 65533임을 의미합니다. 그렇다면 VARCHAR의 최대값이 정말 65533바이트일까요?

CREATE TABLE SQL을 자세히 보시면 두 가지 규칙을 발견할 수 있습니다.

  1. 필드가 비어있을 수 없음(NOT NULL)으로 지정되었습니다.
  2. 테이블에 단 하나의 필드만 존재합니다.

NOT NULL이 VARCHAR의 최대값에 영향을 미칠까요? 이 질문을 한 것 자체가 영향이 있다는 의미겠죠? 실제로 테스트해보겠습니다.

테스트 결과, 필드를 NOT NULL로 설정할 때 VARCHAR는 최대 65533바이트의 내용을 저장할 수 있었습니다. 반면, 필드가 NULL을 허용할 때는 최대 65532바이트의 내용을 저장할 수 있었습니다.

이는 InnoDB가 NULL을 허용하는 필드를 위해 별도의 바이트를 사용하기 때문입니다.

여러 필드의 영향

위에서 NULL이 VARCHAR의 최대값에 영향을 미친다고 설명했습니다. 사실 테이블의 필드 수도 VARCHAR의 최대값에 영향을 미칩니다. MySQL의 오류 메시지를 다시 살펴보겠습니다.

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

여기서 중요한 두 가지 정보가 있습니다. 하나는 사용된 테이블 타입(BLOB 제외)의 최대 행 크기가 65535라는 것이고, 다른 하나는 여기에 저장 오버헤드도 포함되어 있다는 것입니다.

실제로 65535는 BLOB을 제외한 한 행 데이터의 최대 바이트 수입니다. 그렇다면 한 행에 여러 필드가 있다면 어떻게 될까요?

위 테스트에서 int 타입의 필드를 추가하자, 원래 16383개의 utf8mb4 문자를 저장할 수 있었는데 이제는 16382개만 저장할 수 있게 되었습니다. 이는 InnoDB에서 int가 4바이트를 차지하기 때문에 VARCHAR가 하나의 문자를 더 적게 저장할 수 있게 된 것입니다. 문자 수는 (최대 행 바이트 수 - int 필드 바이트 수) / Maxlen = (65532 - 4) / 4 = 16382로 계산됩니다.

다시 한번 65532가 행의 최대 바이트 수이지 VARCHAR의 최대 바이트 수가 아님을 증명했습니다.

그리고 알려진 65535 바이트는 다른 오버헤드를 포함하고 있으므로, 다른 오버헤드는 65535 - 65533 = 2바이트를 차지합니다. 여기서 65533이 왜 그런지 설명하자면, Maxlen이 1인 문자 집합의 최대값이 65533이고, 65532는 문자 집합 Maxlen의 정수배로 65533에 가장 가까운 값이기 때문입니다.

그렇다면 원래의 질문으로 돌아가서, VARCHAR가 정말로 최대 얼마의 문자를 저장할 수 있을까요? 사실 VARCHAR가 저장할 수 있는 문자의 크기는 두 가지에 의존합니다: 테이블에 필드가 몇 개인지, 그리고 NULL을 허용하는지 여부입니다. NULL을 허용하지 않고 단 하나의 VARCHAR 필드만 있다면, 최대로 저장할 수 있는 문자 수는 65533 / Maxlen 입니다.

InnoDB의 규정에 따르면, 테이블 필드에 가변 길이 필드인 VARCHAR가 포함된 경우, VARCHAR의 길이를 저장하기 위해 추가로 2바이트가 필요합니다. 왜 2바이트일까요? 극한의 경우, 테이블에 NULL을 허용하지 않는 단 하나의 VARCHAR 필드만 있는 경우, 이 필드의 길이는 최대 65533바이트가 될 수 있습니다. 이 길이를 저장하려면 최소 2바이트가 필요합니다. 2바이트 = 16비트 = 2^16 = 65536이므로, 길이를 저장하기 위해서는 2바이트가 필요합니다.

태그: MySQL varchar character-set database-optimization InnoDB

6월 5일 02:28에 게시됨