Post

VARCHAR(255) 그냥 써도 문제 없을까?

Intro

이전에 테이블 설계했던 것을 회고하는 글(링크)을 작성하고, 왜 VARCHAR(255)를 사용하는지 알아보기로 했었습니다. 새로운 개인 프로젝트에서 데이터베이스 설계 전에 알아볼 겸 정리합니다.

그런데 명확한 근거를 찾기는 쉽지가 않습니다. 대체로 카더라 식의 정보가 많았습니다. 또 데이터베이스 제품마다 근거가 달라질 수 있어 제가 사용하는 MySQL 위주로 찾아보았습니다.

자료를 찾아본 결과로는 MySQL 최신버전을 사용 중이고, innoDB 를 storage engine으로 사용하면서 설정을 건든게 없다면 그냥 VARCHAR(255) 써도 일반적인 상황에서는 별 문제가 없습니다.

뭔가 단서를 많이 붙였는데, 아래에 제가 궁금해서 찾아본 자료들을 참고해보시면 좋겠습니다.

왜 VARCHAR(255)로 설정하나요?

역사적인 이유

과거 MySQL 5 버전 이전에는 VARCHAR(255) 가 최대값이었고(대다수의 RDBMS도 비슷했다고 합니다), 길이를 확정하기 어려울 때 최대값으로 지정하였습니다.

인덱스(Index)

VARCHAR, TEXT, BLOB과 같은 가변길이 데이터타입(Data Type)은 정확한 크기를 알 수 없기도 하고, 크기가 너무 커서 인덱스를 설정할 수 없는 경우가 있습니다. 그래서 데이터의 앞 부분 일부만 고정된 길이로 인덱스(index key prefix)를 설정하는 기능을 지원합니다.

아래 SQL은 customer 테이블의 name 컬럼(nonbinary string type)에 앞 10글자만 인덱스로 지정하는 예제입니다.

1
CREATE INDEX part_of_name ON customer (name(10));

출처: https://dev.mysql.com/doc/refman/8.0/en/create-index.html

과거에는 innoDB 사용시 prefix 최대값(index key prefix length limit)이 767 bytes 였습니다. 이는 UTF-8 사용 시 한 글자가 최대 3bytes 이고 255글자 x 3bytes = 765 bytes 가 되어 전부 인덱스로 지정할 수 있지만, 256 x 3 = 768 bytes 이므로 제한된 크기를 넘어가게 됩니다.

이후 utf8mb4 등 4bytes 인 문자로 인해 더 큰 크기의 지원이 필요해졌고, innoDB 사용시 prefix 최대값은 row format 설정에 따라 다르긴 하지만 기본 설정값은 3072 bytes 로 증가하였습니다.

inno db row format 상세 내용 문서(링크)

정리

결과적으로 과거 데이터베이스의 제한으로 인해 사용하던 값이 관례로 굳어져서 사용되는 것으로 보입니다.

참고 자료

성능 상의 문제는 없나요?

설정에 따라 달라질 수 있습니다.

Subquery 또는 Window Function을 사용하는 등 여러 상황에서 임시 테이블을 만들 때 설정에 따른 영향을 받을 수 있습니다.

Internal Temporary Table Use in MySQL

Subquery, Window Function 등의 작업 시 임시 테이블이 만들어지는데 이때 두 종류의 임시 테이블이 있습니다. 하나는 in-memory internal temporary table이고, 다른 하나는 on-disk internal temporary table 입니다. 이름에 무엇인지 설명이 나와있으므로 별도의 설명은 생략하겠습니다.

in-memory internal temporary table

MySQL에서 in-memory internal temporary table 을 관리하는 storage engine으로는 TempTableMEMORY 가 있습니다.

MEMORY storage engine 사용 시에는 VARCHAR 에 설정한 최대 길이까지 남는 부분을 채워서 고정 길이의 CHAR로 만듭니다. 그래서 임시 테이블을 만들 때 무조건 VARCHAR 최대 길이만큼 메모리를 사용하게 돼서 자원을 비효율적으로 사용하게 됩니다.

TempTable storage engine은 MySQL 8 버전에서 도입됐으며, MEMORY storage engine 과는 달리 최대 길이까지 남는 부분을 채우는 패딩을 하지 않고 VARCHAR 등 가변길이 데이터타입을 효율적으로 저장합니다.

MySQL 8 에서 기본값은 TempTable 이므로 굳이 바꾸지 않는 이상은 고려할 필요가 없겠습니다.

internal_tmp_mem_storage_engine 설정값 문서(링크)

on-disk internal temporary table

MySQL 에서 on-disk internal temporary table을 관리하는 storage engine으로는 innoDBMyISAM이 있습니다.

innoDB 와 MyISAM 에서는 MEMORY storage engine 처럼 VARCHAR 의 최대 길이로 고정해서 사용하도록 설정할 수도 있고, TempTable 처럼 고정하지 않고 메모리를 효율적으로 사용하도록 설정할 수도 있습니다.

innoDB의 경우 row format을 설정하여 이를 전환할 수 있는데, 기본값(DYNAMIC)이 메모리를 효율적으로 사용하는 설정입니다.

inno db row format 설정값 문서(링크)
inno db row format 상세 내용 문서(링크)

MySQL 8.0.15까지는 CTE를 사용하는 경우 등 MyISAM을 강제하는 경우도 있지만, MySQL 8.0.16 부터는 innoDB 외에는 사용할 수 없습니다. 최신 버전 사용시에는 row format만 잘 고려하면 되겠습니다.

on-disk 만 사용되는 경우 등 자세한 내용은 레퍼런스 문서(링크)를 참고해주세요.

예외적인 경우의 성능 문제

Optimizing Data Size 문서(링크)를 보면, 아래와 같은 내용이 있습니다.

The compact family of row formats, which includes COMPACT, DYNAMIC, and COMPRESSED, decreases row storage space at the cost of increasing CPU use for some operations. If your workload is a typical one that is limited by cache hit rates and disk speed it is likely to be faster. If it is a rare case that is limited by CPU speed, it might be slower.

innoDB 의 row format 설정값이 기본값인 DYNAMIC을 포함해서 COMPACT 이거나 COMPRESSED 일 때, row 저장 공간을 절약하기 위해 CPU 작업이 증가하게 됩니다. 작업이 cache hit rates 나 disk speed 에 의해 제한되는 경우 더 빨라지지만, CPU 속도에 의해서 제한되는 작업의 경우 더 느려질 수도 있습니다.

CPU 속도가 문제가 되는 수준의 연산 작업을 하는거면, 빅데이터 쪽으로 넘어가야 하지 않을까… 어렴풋이 추측해봅니다.

참고 자료

결론

시작부터 결론을 말씀드리기는 했지만, innoDB 외의 다른 storage engine 또는 다른 데이터베이스를 사용하는 경우는 전혀 고려되지 않은 결론이었습니다. 최대한 데이터 길이에 맞게 잘 설정하는게 가장 좋기는 하겠지만, 그게 쉽지 않으니까 과거부터 VARCHAR(255)를 사용해 왔겠죠? 사용하는 데이터베이스의 매뉴얼을 잘 보고 결정해야겠습니다. 다른 데이터베이스로 변경할 때 좀 괴롭기는 하겠습니다.

저는 MySQL을 사용하는 동안 설정을 변경할 이유가 없고, innoDB를 storage engine으로 사용하는 경우, 길이 설정이 애매할 때 VARCHAR(255)를 사용할 계획입니다.

Outro

VARCHAR(255) 써도 되는거야 마는거야 정도만 알고 싶은 마음과, 더 깊게 알고 싶은 마음이 오락가락해서 내용의 깊이도 뭔가 애매한거 같습니다.

더 깊이있는 내용이 필요할 때 위에 있는 키워드로 더 찾아보는걸로 하고, 이만 마무리하겠습니다.

This post is licensed under CC BY 4.0 by the author.