기본 CharacterSet 의 변경 (latin1 > utf8mb4)
버젼별 비교
-
5.7
mysql 5.7 [localhost] {msandbox} ((none)) > show session variables like '%char%'; +--------------------------+----------------------------------------+ | Variable_name | Value | +--------------------------+----------------------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | latin1 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /MySQL/binaries/5.7.24/share/charsets/ | +--------------------------+----------------------------------------+ 8 rows in set (0.01 sec) mysql 5.7 [localhost] {msandbox} ((none)) > select * from information_schema.COLLATIONS where CHARACTER_SET_NAME='latin1' and IS_DEFAULT='Yes'; +-------------------+--------------------+----+------------+-------------+---------+ | COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN | +-------------------+--------------------+----+------------+-------------+---------+ | latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 | +-------------------+--------------------+----+------------+-------------+---------+ 1 row in set (0.00 sec)
-
8.0
mysql 8.0 [localhost] {msandbox} ((none)) > show session variables like '%char%'; +--------------------------+----------------------------------------+ | Variable_name | Value | +--------------------------+----------------------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8 | | character_sets_dir | /MySQL/binaries/8.0.13/share/charsets/ | +--------------------------+----------------------------------------+ 8 rows in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > select * from information_schema.COLLATIONS where CHARACTER_SET_NAME='utf8mb4' and IS_DEFAULT='Yes'; +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN | PAD_ATTRIBUTE | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ 1 row in set (0.01 sec)
드디어 기본 character set 과 collation 이 지긋지긋한 latin1 (latin1_swedish_ci) 에서 utf8mb4 (utf8mb4_0900_ai_ci) 로 변경이 되었고, 모든 작업이 utf8mb4 character set을 기본으로 동작하게 되었다. 기존에는 my.cnf 에 character-set-server = [utf8 euckr utf8mb4] 를 넣어 해당 mysqld의 기본 character set 을 지정해야만 했었다.
기본 collation의 변경
기존의 collation 에서 ‘ci’ (case insensitive (대소문자 구분하지 않음)) 와 ‘cs 혹은 bin’ (case sensitive(대소문자 구분)) 만을 지원하였다면 추가적으로 Accent 에 관해서도 지원하게 되었다. 또한 PAD의 default 값이 변경되어, 사용 혹은 Migration후 주의깊게 사용되어져야 한다.
MySQL 8.0의 default collation은 utf8mb4_0900_ai_ci 이고, 이는 다음과 같은 내용을 포함한다
* collation의 character set은 utf8mb4 이다. (utf8mb4)
* Unicod 9.0의 문자를 표현한다. (0900)
* Accent Insensitive Mode로 동작한다. (ai)
* Case Insensitive Mode로 동작한다. (ci)
ai, as 의 생성
-
ai : Accent Insensitive
-
ac : Accent Sensitive
mysql 8.0 [localhost] {msandbox} ((none)) > SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_0900_ai_ci | +--------------------------------+ 1 row in set (0.00 sec) -- 기본 utf8mb4의 collation인 utf8mb4_0900_ai_ci는 Accent Insensitive 모드이다. mysql 8.0 [localhost] {msandbox} ((none)) > select if('ê' = 'e','True','False'); +-------------------------------+ | if('ê' = 'e','True','False') | +-------------------------------+ | True | +-------------------------------+ 1 row in set (0.00 sec) --^^ Accent Insensitive 모드에서는 if('ê' = 'e') 의 결과가 참이된다. mysql 8.0 [localhost] {msandbox} ((none)) > SET NAMES utf8mb4 COLLATE utf8mb4_0900_as_ci; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_0900_as_ci | +--------------------------------+ 1 row in set (0.00 sec) -- Accent sensitive 모드로 변경해보자. mysql 8.0 [localhost] {msandbox} ((none)) > select if('ê' = 'e','True','False'); +-------------------------------+ | if('ê' = 'e','True','False') | +-------------------------------+ | False | +-------------------------------+ 1 row in set (0.00 sec) --^^ Accent Sensitive 모드에서는 if('ê' = 'e') 의 결과가 거짓이된다.
PAD의 추가
-
MySQL은 전통적으로 데이터 값의 뒤 공백을 제거하고 비교하는 방법을 사용해왔다. 하지만 8.0부터는 Collation 에 따라, ORACLE 과 비슷하게 공백을 제거하지 않고 비교가 가능하다.
mysql 8.0 [localhost] {msandbox} ((none)) > select * from information_schema.collations where COLLATION_NAME like 'utf8mb4_0900%' or COLLATION_NAME = 'utf8mb4_bin' or COLLATION_NAME like 'utf8mb4_general%'; +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | COLLATION_NAME | CHARACTER_SET_NAME | ID | IS_DEFAULT | IS_COMPILED | SORTLEN | PAD_ATTRIBUTE | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ | utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | PAD SPACE | | utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 | PAD SPACE | | utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD | | utf8mb4_0900_as_cs | utf8mb4 | 278 | | Yes | 0 | NO PAD | | utf8mb4_0900_as_ci | utf8mb4 | 305 | | Yes | 0 | NO PAD | +--------------------+--------------------+-----+------------+-------------+---------+---------------+ 5 rows in set (0.00 sec)
-
기본적으로 collation을 따로 지정하지 않고 사용하는 경우 5.7과 8.0의 동작방식이 달라질 수 있음을 확인해야한다.
5.7의 경우, 뒤에 나오는 모든 공백을 기본적으로 제거하고 비교하지만, 8.0의 경우 utf8mb4 character의 default collation 이 ‘NO PAD’ 형식으로 동작함으로 공백을 제거하지 않고 비교함을 유의해야 한다.
이는 WAS 의 connection string에서도 꼭 connectionCollation 을 지정해야하는 이유이기도 하다.
- https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-charsets.html
-
버젼별 비교
-
5.7
-- 5.7의 경우, PADDING에 대한 옵션이 존재하지 않음으로 모두 PAD SPACE (뒤의 공백제거) 로 처리된다. mysql 5.7 [localhost] {msandbox} (test) > SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_general_ci | +--------------------------------+ 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > SELECT hex('a ' ), hex ('a'), 'a ' = 'a'; +------------+-----------+------------+ | hex('a ' ) | hex ('a') | 'a ' = 'a' | +------------+-----------+------------+ | 6120 | 61 | 1 | +------------+-----------+------------+ 1 row in set (0.01 sec) --^^ PAD SPACE로 사용됨으로 'a ' = 'a' 가 같음을 유의하자. mysql 5.7 [localhost] {msandbox} (test) > SET NAMES utf8mb4 COLLATE utf8mb4_bin; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_bin | +--------------------------------+ 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > SELECT hex('a ' ), hex ('a'), 'a ' = 'a'; +------------+-----------+------------+ | hex('a ' ) | hex ('a') | 'a ' = 'a' | +------------+-----------+------------+ | 6120 | 61 | 1 | +------------+-----------+------------+ 1 row in set (0.00 sec)
-
8.0
-- 8.0의 경우, PADDING에 대한 옵션이 collation마다 다름으로 주의가 필요하다. mysql 8.0 [localhost] {msandbox} ((none)) > SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_0900_ai_ci | +--------------------------------+ 1 row in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT hex('a ' ), hex ('a'), 'a ' = 'a'; +------------+-----------+------------+ | hex('a ' ) | hex ('a') | 'a ' = 'a' | +------------+-----------+------------+ | 6120 | 61 | 0 | +------------+-----------+------------+ 1 row in set (0.00 sec) --^^ NO PAD로 사용됨으로 'a ' = 'a' 가 다름을 유의하자. mysql 8.0 [localhost] {msandbox} ((none)) > SET NAMES utf8mb4 COLLATE utf8mb4_bin; Query OK, 0 rows affected (0.01 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT @@session.collation_connection; +--------------------------------+ | @@session.collation_connection | +--------------------------------+ | utf8mb4_bin | +--------------------------------+ 1 row in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > SELECT hex('a ' ), hex ('a'), 'a ' = 'a'; +------------+-----------+------------+ | hex('a ' ) | hex ('a') | 'a ' = 'a' | +------------+-----------+------------+ | 6120 | 61 | 1 | +------------+-----------+------------+ 1 row in set (0.00 sec)
-
SMP (Supplementary Multilingual Plane) 의 확장
-
MySQL 을 사용함에 있어서 아주 유명한 Bug가 존재했다. (Case Insensitive collation을 사용할때, 많은 이모지들이 같은 값으로 치부되는 버그)
- https://bugs.mysql.com/bug.php?id=87700
-
이를 해결하기 위해서는 5.2 이상의 unicode를 지원하는 utf8mb4_unicode_520_ci collation을 사용하거나, binary 형태로 변경하여 사용을 해야하는 번거로움이 있었습니다. 하지만 8.0의 기본 collation 인 utf8mb4_0900_ai_ci 가 unicode 9.0을 지원하면서 부터 많은 추가적인 emoji의 연산이 가능해졌다.
-
버젼별비교
-
5.7
mysql 5.7 [localhost] {msandbox} (test) > SET NAMES utf8mb4; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > show session variables like 'collation_connection'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | collation_connection | utf8mb4_general_ci | +----------------------+--------------------+ 1 row in set (0.01 sec) mysql 5.7 [localhost] {msandbox} (test) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD HEX('?'): F09F8DBA WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD '?' = '?': 1 1 row in set (0.00 sec) --^^ 5.7까지 utf8mb4의 기본 collation의 emoji 비교가 정상적으로 이루어지지 않았다. HEX값이 다르더라도, collation을 비교할 수 있는 WEIGHT_STRING이 값을 처리하지 못했다. mysql 5.7 [localhost] {msandbox} (test) > set names utf8mb4 collate utf8mb4_unicode_ci; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > show session variables like 'collation_connection'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | collation_connection | utf8mb4_unicode_ci | +----------------------+--------------------+ 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD HEX('?'): F09F8DBA WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD '?' = '?': 1 1 row in set (0.00 sec) --^^ 기본으로 제공되는 unicode에서도 같은 문제가 발생되었다. mysql 5.7 [localhost] {msandbox} (test) > set names utf8mb4 collate utf8mb4_unicode_520_ci; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > show session variables like 'collation_connection'; +----------------------+------------------------+ | Variable_name | Value | +----------------------+------------------------+ | collation_connection | utf8mb4_unicode_520_ci | +----------------------+------------------------+ 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): ���c HEX(WEIGHT_STRING('?')): FBC3F363 HEX('?'): F09F8DBA WEIGHT_STRING('?'): ���z HEX(WEIGHT_STRING('?')): FBC3F37A '?' = '?': 0 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > set names utf8mb4 collate utf8mb4_bin; Query OK, 0 rows affected (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > show session variables like 'collation_connection'; +----------------------+-------------+ | Variable_name | Value | +----------------------+-------------+ | collation_connection | utf8mb4_bin | +----------------------+-------------+ 1 row in set (0.00 sec) mysql 5.7 [localhost] {msandbox} (test) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): �c HEX(WEIGHT_STRING('?')): 01F363 HEX('?'): F09F8DBA WEIGHT_STRING('?'): �z HEX(WEIGHT_STRING('?')): 01F37A '?' = '?': 0 1 row in set (0.00 sec) --^^ 해당문제를 피하기 위해서는 unicod 5.2가 구현된 utf8mb4_unicode_520_ci 혹은 binary 형태로 사용해야 했다.
-
8.0
mysql 8.0 [localhost] {msandbox} ((none)) > SET NAMES utf8mb4; Query OK, 0 rows affected (0.01 sec) mysql 8.0 [localhost] {msandbox} ((none)) > show session variables like 'collation_connection'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | collation_connection | utf8mb4_0900_ai_ci | +----------------------+--------------------+ 1 row in set (0.03 sec) mysql 8.0 [localhost] {msandbox} ((none)) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): HEX(WEIGHT_STRING('?')): 130C HEX('?'): F09F8DBA WEIGHT_STRING('?'): # HEX(WEIGHT_STRING('?')): 1323 '?' = '?': 0 1 row in set (0.00 sec) --^^ 8.0의 경우, 기본적으로 unicode9.0을 사용함으로, 해당문제를 해결하였다. mysql 8.0 [localhost] {msandbox} ((none)) > set names utf8mb4 collate utf8mb4_unicode_ci; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > show session variables like 'collation_connection'; +----------------------+--------------------+ | Variable_name | Value | +----------------------+--------------------+ | collation_connection | utf8mb4_unicode_ci | +----------------------+--------------------+ 1 row in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD HEX('?'): F09F8DBA WEIGHT_STRING('?'): �� HEX(WEIGHT_STRING('?')): FFFD '?' = '?': 1 1 row in set (0.00 sec) --^^ 여전히 기본으로 제공되는 unicode에서도 문제가 발생된다. 이는 하위 호환성을 위함이다. mysql 8.0 [localhost] {msandbox} ((none)) > set names utf8mb4 collate utf8mb4_unicode_520_ci; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > show session variables like 'collation_connection'; +----------------------+------------------------+ | Variable_name | Value | +----------------------+------------------------+ | collation_connection | utf8mb4_unicode_520_ci | +----------------------+------------------------+ 1 row in set (0.01 sec) mysql 8.0 [localhost] {msandbox} ((none)) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): ���c HEX(WEIGHT_STRING('?')): FBC3F363 HEX('?'): F09F8DBA WEIGHT_STRING('?'): ���z HEX(WEIGHT_STRING('?')): FBC3F37A '?' = '?': 0 1 row in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > set names utf8mb4 collate utf8mb4_bin; Query OK, 0 rows affected (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > show session variables like 'collation_connection'; +----------------------+-------------+ | Variable_name | Value | +----------------------+-------------+ | collation_connection | utf8mb4_bin | +----------------------+-------------+ 1 row in set (0.00 sec) mysql 8.0 [localhost] {msandbox} ((none)) > select HEX('🍣'), WEIGHT_STRING('🍣'), HEX(WEIGHT_STRING('🍣')), HEX('🍺'), WEIGHT_STRING('🍺'), HEX(WEIGHT_STRING('🍺')), '🍣' = '🍺' \G *************************** 1. row *************************** HEX('?'): F09F8DA3 WEIGHT_STRING('?'): �c HEX(WEIGHT_STRING('?')): 01F363 HEX('?'): F09F8DBA WEIGHT_STRING('?'): �z HEX(WEIGHT_STRING('?')): 01F37A '?' = '?': 0 1 row in set (0.00 sec)
-