MySQL에서 테이블을 만들 때 varchar(255)
를 자주 사용했다.
varchar가 가변길이 타입으로 char에 비해 실제 저장한 데이터의 크기만큼 저장한다고 알고 있었다. 그런데 왜 하필 255인지는 생각해본 적이 없어 알아보았다.
MySQL 8.0의 공식 문서를 보면 다음과 같이 적혀있다.
Values in VARCHAR columns are variable-length strings. The length can be specified as a value from 0 to 65,535. The effective maximum length of a VARCHAR is subject to the maximum row size (65,535 bytes, which is shared among all columns) and the character set used.
In contrast to CHAR, VARCHAR values are stored as a 1-byte or 2-byte length prefix plus data. The length prefix indicates the number of bytes in the value. A column uses one length byte if values require no more than 255 bytes, two length bytes if values may require more than 255 bytes.
우선, 5.0.3 이전까지는 varchar의 최대 길이는 255 byte였다고 한다. 5.0.3부터는 65535 byte라고 한다.
그리고 varchar는 (현재 저장되어 있는 값의 byte) + (그 값의 길이를 나타내는 byte) 이 두 개를 합해서 저장하는 데에 사용한다고 한다. 예를 들어 'apple'을 저장하면 5 byte + 1 byte 총 6 byte가 저장되는 것이다.
그런데 만약 저장할 값의 길이가 255를 넘어버리면 이것의 길이는 1 byte로 표현할 수 없게 된다. 만약 300 byte 길이의 값을 저장한다고 하면, 이것의 길이는 2 byte로 표현해야 한다. 따라서 300 byte + 2 byte = 302 byte를 저장하게 된다.
Now, how does VARCHAR work? If you specify it as VARCHAR(255), that means that the column will reserve 1 byte + length of the string bytes. That 1 byte indicates how long the string is. 1 byte = you can have from 0 - 255 values stored (2 to the power of 8 = 256).
더 찾아보니, 만약 만든 varchar의 스키마가 255 이하라면 1 byte를 예약하고, 255를 초과한다면 2 byte를 예약하는 데에 사용한다고 한다. 즉 실제 데이터의 길이와 상관없이 스키마에 따라 데이터 길이 byte를 1 byte를 사용할지 2 byte를 사용할지 결정된다는 뜻이다.
funny thing is, it's not just wasted space. It also contributes to processing overhead and using extra RAM when you want to read something.
따라서 row의 갯수가 많아지면 공간의 낭비, 램 낭비가 이루어진다고 한다.
더 찾아보니 이런 내용도 있다.
In fact, if I remember correctly, I recall someone modifying the data dictionary with an hexadecimal editor in order to change something like a VARCHAR(50) into a VARCHAR(100), so it could be done dynamically (normally, that requires a table reconstruction). And that was possible, because the actual data was not affected by that change.
That is not true with VARCHAR(256), because then 2 bytes (at least) for the length are always required.
즉 varchar(50)
에서 varchar(100)
로 변경할 때 잘 바뀌었다고 한다. 왜냐하면 둘 다 1 byte + 데이터의 길이 byte만 필요하기 때문에 실제 데이터에 영향을 미치지 않기 때문이다.
하지만 varchar(256)
은 안된다고 한다. 왜냐하면 위에서 설명했듯이 2 byte가 항상 필요하기 때문에 데이터 구조를 바꿔야하기 때문이다.
While InnoDB may store a varchar in a dynamic way, that is not true for other engines. MyISAM has a fixed row size format, and MEMORY tables are always fixed in size. Should we care about those other engines? Yes, we should, because even if we do not use them directly, MEMORY tables are very commonly used for intermediate results (temporary tables on memory), and as the results are not known beforehand, the table has to be created with the maximum size possible -VARCHAR(255) if that is our type. If you can think about the wasted space, if we are using MySQL's 'utf8' charset encoding, MEMORY will reserve 2 bytes for the length + 3 * 255 bytes per row (for values that may only take a few bytes on InnoDB).
만약 InnoDB를 사용하면 varchar을 동적으로 최적화해서 적게 저장할 수 있다고 한다. 하지만 MyISAM은 스키마에 맞게 fix된 row size를 사용하고, MEMORY는 고정된 테이블 size를 사용한다.
그렇다면 다른 엔진을 고려할 필요가 있는가? 그렇다고 한다. 중간 연산에 MEMORY 엔진이 일반적으로 사용되기 때문이다. 만약 utf8 인코딩을 사용한다고 하면 MEMORY는 row당 2byte + 3 * 255 byte의 공간을 예약한다. 3은 utf8 인코딩이기 때문에 한 글자당 3 byte를 사용해서다.
So the general piece of advice is to use the smallest type possible, because it can potentially create performance or management problems otherwise. A VARCHAR(100) is better than VARCHAR(255) (although a VARCHAR(20) would be better), even if you do not know the exact length. Try to be because, unless the table is too large, you can always change the definition later.
따라서 가능한 요구 사항에 맞춰 작은 타입을 사용하라고 한다. 왜냐하면 성능이나 관리 이슈가 있을 수 있기 때문이라고 한다. 테이블이 너무 크지 않은 이상 나중에라도 정의를 바꿀 수 있으니 보수적으로 접근하라고 한다.
근데 이런 의견도 존재한다.
Forget about the 1- versus 2-byte prefix on VARCHARs.
It impacts performance by a minuscule amount.
It is "2" more often than the obvious rule says.
How much performance hit? It is hard to predict; generally, it is not worth worrying about. (The Question was about performance, I have tried to list all cases where the number in VARCHAR matters, even a little.)
성능 이슈는 거의 느끼기 어렵고, 또 성능이 어떻게 되는지 예측하기 어렵다고 한다.
Don't blindly use 255 (or 256); do what makes sense for the schema. If you do need 255 (or 1024 or whatever), go ahead in use it. I am merely pointing out some downsides.
하지만 어쨌든 255를 막 사용하지 말고, 스키마에 맞게 만들라고 한다.
우선 varchar(255)
가 사용되는 이유는 관습적인 이유가 큰 것으로 보인다. MySQL 5.0.3 이전 버전까지는 그것이 최대 길이였으므로 만약 스키마를 varchar(100)
으로 설정했다가 그것보다 큰 데이터를 저장하게 된다면 스키마를 변경해야 하니까 다들 그렇게 쓴 것으로 생각한다.
하지만 varchar(100)
으로 설정했다고 해도, 테이블 사이즈가 너무 큰 것이 아니면 그 이상의 byte로 변경 가능하니 (256 이상은 안됨) 스키마에 맞게 보수적으로 설정하라는 의견을 볼 수 있었다.
또 다른 이유는, 255가 넘어가면 1 byte를 추가적으로 사용하여 2byte를 사용하게 되기 때문에(실제로 저장된 문자열은 255 byte 이하임에도 불구하고) 공간 낭비, 램 낭비가 이루어진다고 한다.
그러면 어떻게 해야 하는가?
255를 막 쓰지 말고 요구 사항에 맞게 스키마를 설정하라는 것이 공통된 의견인 것 같다.
나도 알지 못하고 막 사용했는데 한 번 스키마를 점검해봐야겠다.
https://dev.mysql.com/doc/refman/8.0/en/char.html
https://stackoverflow.com/questions/5898904/mysql-different-treatment-between-varchar255-and-varchar65536
https://dba.stackexchange.com/questions/76469/mysql-varchar-length-and-performance