문자셋(charset)

문자셋 문제는 항상 개발자를 괴롭힌다. 나도 문자셋에 대해서는 제대로 이해하지 못하고 사용하고 있었던 것이 사실이다. 이 내용을 작성하면서도 매우 명쾌하게 모든 사실을 이해한 것은 아니지만, 그래도 도움이 되고자 글을 남긴다.

예전엔 EUC-KR 이라고 흔히 완성형 한글이라고 불렀던 형태의 인코딩을 사용했었다. EUC-CN, EUC-JP, EUC-TW 등의 인코딩 방식도 있었던 것으로 보아 나름 표준이었던 것 같다. 조합형 한글, 확장 완성형 한글 등의 방식이 있었지만 일부 글자를 표현하지 못한다던가 하는 각각의 장단점이 있었다.

지금에 이르러서는 UTF-8이라는 헝태로 통일되어 사용되어지고 있는데, 한글은 한자, 일본어 등을 포함한 모든 유니코드 문자를 모두 표현할 수 있다는 장점이 있기 때문이다.

위키백과 “EUC-KR”(http://ko.wikipedia.org/wiki/EUC-KR)
위키백과 “UTF-8” (http://ko.wikipedia.org/wiki/UTF-8)

MySQL도 4.0 에서 4.1 로 넘어가면서 기존의 문자열 타입의 컬럼의 크기를 나타내는 방식이 byte 수에서 글자 수로 변경되었다.

예를 들어, varchar(10) 이 기존에 10 bytes 로 영문 10자 또는 한글 5자(한 글자에 2byte)를 넣을 수 있다는 의미였는데, 문자에 상관 없이 10글자를 넣을 수 있다는 의미로 변경된 것이다.

문자열 크기 변경 때문에 당시 4.0 에서 4.1 로 마이그레이션 하면서 데이터를 많이 날려먹었던 기억이 난다. 멀티바이트 컬럼의 크기가 절반으로 줄어서 생긴 문제라고 하는데, 당시에는 제대로 이해하지 못하고 넘어갔었다…
어쨋든, 상황은 리눅스 콘솔에서 INSERT를 시도하면 지정한 컬럼 크기 만큼 한글이 들어가지 않고 짤려서 나오는 증상이 발생하면서 부터 시작됐다.


위의 내용대로라면 char 컬럼의 크기는 한글/영문 구분없이 10글자가 들어갈 수 있어야 하는데, 실제 결과는 한글 3 + 1/3 글자가 들어가는 것이었다.


처음엔 단순히 utf8 문자셋의 한글이 3 bytes 를 차지하기 때문에 varchar(10) 안에 10 bytes 만큼만 기록되는 것이다라고 생각을 했었다.

하지만 문제는 문자셋 세팅에 있었다. 리눅스 콘솔 자체의 문자셋이 utf8 인 것과 별개로, MySQL 클라이언트의 문자셋 설정이 latin1 로 되어있었기 때문이다.


latin1 문자셋은 1글자가 1 byte 이다. utf8로 입력된 문자열 ‘가나다라마바사아자차’를 MySQL Client가 latin1 형태로 Server에 전달하다 보니, 한글 1글자당 3 bytes로 인식되어 결국, latin1 10 글자 만큼만 저장된 것인데, 마치 varchar(10)이 10 bytes 크기를 가지기 때문인 것 처럼 판단하도록 만들어버린 것이다.

이런 경우에는 간단히 아래 명령어로 해결이 가능하다.

MySQL Client의 세팅이 utf8로 정상적으로 적용된 후에, 기존에 입력되었던 row를 조회해보면 아예 깨져서 나오는 것을 볼 수가 있다. latin1 문자셋으로 입력되었기 때문에 latin1 환경에서 보면 한글이 보일지 모르지만, 윈래 의도했던 utf8 로 보면 전혀 맞지 않는 형태로 표현이 되는 것이다.


정상적인 설정에서 한글을 다시 입력해보면,

정상적으로 10글자가 표시되는 것을 볼 수가 있다.

거꾸로 utf8 환경에서 정상적으로 입력한 row 도 latin1 환경에서 보면 제대로 보이지 않는다.
문자셋 혼동의 결과를 정확하게 판단하기 위해 다시 한 번 테스트.


위의 show variables 결과에서 볼 수 있듯이, 문자셋 환경도 Server, Client, Connection 등의 다양한 부분에 지정할 수 있다.

예를 들어 server에는 utf8로 저장되어있는 데이터지만, 콘솔의 환경이 euc-kr 일 때,

로 설정하고 사용하면 문자셋 같의 변환을 mysql이 알아서 해준다. 

추가로, MySQL 을 설치하고 초기 설정 할 때도 기본 문자셋을 잘 지정해 놓는 것이 중요하다.
위의 예시에서 server와 database 설정이 latin1로 되어있기 때문에 my.ini 환경설정에서 해당 부분을 수정 후 서비스를 재시작 하였다.

결과적으로, MySQL의 문자열 컬럼 크기는 byte가 아니라 글자 수라는 것이 사실이며,
사용자는 클라이언트, 서버, 커넥션의 문자셋 환경을 잘 맞춰주어야 원하는 결과를 얻을 수 있다는 것이다.

문자셋 이 개샛기!

]]>

도큐멘트 에 올린 글

댓글 남기기