과정을 즐기자

무작정 데이터 타입을 VARCHAR(16683)로 하면 안되는 이유 본문

Database

무작정 데이터 타입을 VARCHAR(16683)로 하면 안되는 이유

320Hwany 2023. 9. 4. 15:28

이번 글은 MySQL과 InnoDB 스토리지 엔진을 기준으로 작성하였습니다.

 

MySQL에는 여러 데이터 타입이 있습니다. 숫자형 데이터 타입, 문자열 데이터 타입, 날짜 시간 데이터 타입 등..

이 중에서 문자열 데이터 타입의 종류에는 CHAR, VARCHAR, TEXT 등이 있습니다.

CHAR는 고정 크기 문자열 방식이고 VARCHAR는 가변 크기 문자열 방식이고 TEXT는 긴 문자열을 저장할 때 사용합니다.

 

이때 한가지 의문이 듭니다.

VARCHAR가 가변 크기 문자열 방식이라면 TEXT를 사용하지 않고 그냥 최대 크기인 VARCHAR(16683)로 (65535 bytes)

선언하면 되지 않을까요? 어차피 10글자만 입력하면 실질적인 10글자인 40bytes를 저장하고 나머지 4byte는 길이정보로

사용하여 VARCHAR(16683)로 선언하더라도 44bytes만 사용하게 됩니다.

이렇게 아예 크게 선언한다고 저장 공간을 더 많이 사용하는 것도 아니고 나중에 더 큰 문자열을 받을 수도 있으니

유연한 설계가 아닐까요?

VARCHAR

여기서 한 가지 놓친 사실이 있는데 저장 공간을 많이 사용하지 않는다는 것에서 '저장 공간'은 SSD나 디스크를 말합니다.

즉, VARCHAR(16683)로 선언하든 VARCHAR(50)으로 선언하든 10글자만 입력하면 SSD나 디스크에 저장되는

데이터의 크기는 모두 같습니다.

 

하지만 메모리 버퍼에서의 저장은 달라집니다. MySQL과 InnoDB 스토리지 엔진은 메모리 포인터를 이용해서 레코드 데이터를

주고 받습니다. 메모리 버퍼에 실제 레코드의 크기에 상관없이 최대 크기로 할당합니다.

즉, VARCHAR(16683)로 선언하면 (16683 * 4 + 4) bytes의 공간을 메모리 버퍼에 미리 할당한다는 것입니다. (utf8mb4 기준)

그래서 가변 길이 방식이라고 무작정 VARCHAR(16683)로 선언하면 메모리 부족 문제가 발생할 수 있습니다.

 

그렇다면 메모리 버퍼에 미리 최대 크기로 할당해놓은 이유가 무엇일까요?

바로 여러 커넥션에서 공유해서 사용할 수 있도록 하기 위함입니다.

메모리 버퍼에 처음 할당을 해놓고 여러 커넥션이 재사용할 수 있게 했습니다.

따라서 가변 방식의 장점을 제대로 사용하기위해서는 무작정 VARCHAR(16683)로 선언해서는 안되는 것입니다.

TEXT

위에서 VARCHAR는 메모리 버퍼에 최대 레코드의 크기만큼 미리 할당한다고 하였습니다.

그렇다면 정말 긴 문자열을 저장해야 한다면 메모리에 미리 할당하는 것은 문제가 될 수 있습니다.

문자열 데이터 타입 TEXT는 메모리에 미리 할당을 하지 않고 매번 레코드를 읽고 쓸 때마다 필요한 만큼 

메모리를 할당합니다.

만약에 100글자를 저장한다고 해도 메모리 버퍼 공간에는 TEXT 값을 위한 포인터 공간 8 bytes, 헤더 4bytes 

총 12bytes만 저장하고 레코드를 읽고 쓸 때 필요한 만큼 메모리를 할당하게 됩니다.

정리

지금까지 살펴본 동작 방식으로 VARCHAR와 TEXT를 각각 언제 사용하면 될 지를 정리해보겠습니다.

VARCHAR는 메모리 버퍼에 미리 할당하기 때문에 우선 문자열의 길이가 너무 길면 안됩니다.

TEXT는 메모리 버퍼에 미리 할당하지 않고 레코드를 읽고 쓸 때 할당하므로 문자열의 길이가 긴 데이터를 저장할 때 적합합니다.

메모리 버퍼에 저장된 데이터는 여러 커넥션이 공유해서 사용할 수 있으므로 해당 컬럼이 자주 필요한 경우VARCHAR가

적합합니다.

 

참고한 자료

 

VARCHAR vs TEXT

개요

medium.com