Unicode(유니코드)

  • 유니코드는 전 세계의 모든 문자, 기호, 이모지 등을 컴퓨터에서 일관되게 표현하고 다룰 수 있게 만든 국제 표준 규약 이다.
  • 세상의 모든 글자에 고유한 ID를 하나씩 부여한 거대한 문자 백과사전 이라고도 볼 수 있다.

1. 탄생 배경

  • 과거에는 나라 또는 시스템마다 문자를 표현하는 방식(인코딩)이 제각각이었다.
    • 때문에 데이터를 주고 받으면 글자가 깨지는 현상이 비일비재했다.
    • 이를 해결하기 위해서 전 세계적으로 유일한 코드 번호를 부여한 것이다.

2. UTF-8

  • Unicode Transformasion Format-8-bit 의 준 말로, 유니코드의 코드 포인트를 실제 컴퓨터의 바이트 형태로 저장하는 가장 대중적인 인코딩 방식이다.

2-1. 핵심 : 가변 길이 인코딩

  • 가장 큰 특징은, 문자에 부여된 범위에 따라 저장에 사용하는 바이트 수를 효율적으로 조절하는 가변 길이 인코딩 이라는 점이다.
    • 1바이트 : 영어, 숫자 등 (ASCII 코드와 동일)
    • 2바이트 : 유럽 문자, 아랍어 등
    • 3바이트 : 한글, 한자 등 대부분의 현대 문자
    • 4바이트 : 고대 문자, 수학 기호, 대부분의 이모지 등

utf8mb4_0900_ai_ci 🆚 utf8mb4_general_ci

1. utf8mb4

  • utf8 : 문자를 저장하는 기반 기술이, UTF-8 인코딩 방식임을 의미한다.
  • mb4 : most bytes 4 의 줄임말로, 하나의 문자를 표현하기 위해 최대 4바이트까지 사용할 수 있다는 의미이다.
  • 이를 Character Set 이라고 한다.

1-1. utf8mb4가 탄생한 이유

  • 과거 MySQL의 utf8 캐릭터 셋은 UTF-8 표준을 일부만 구현하여 최대 3바이트까지만 지원하였다.
    • 때문에 4바이트가 필요한 문자들을 저장할 수 없었다.
  • 이를 해결하기 위해서 utf8mb4가 탄생하였고, 그 결과 모든 문자를 문제 없이 저장할 수 있게 되었다.

2. 0900_ai_ci

  • 현재 MySQL 8.0의 기본 설정 값이다.
  • 0900 : 기반이 되는 유니코드 표준 버전이 9.0.0 임을 의미한다.
  • ai(Accent Insensitive) : 악센트 부호(á, à 등)를 원본 문자와 동일하게 취급한다.
    • ex) a = á
  • ci(Case Insensitive) : 대소문자를 동일하게 취급한다.
    • ex) A = a
  • 이러한 설정을 Collation 이라고 한다.

3. general_ci

  • 과거에 속도를 중시하여 널리 사용되었던 Collation이다.
  • general : 특정 언어 규칙을 엄격하게 따르지 않는 일반적인(General) ****비교 규칙을 사용한다.
    • 즉, 속도를 높이기 위해 정렬 규칙을 단순화한 방식이다.
    • ex) 독일어에서 ßss와 동일하게 취급되어야 하나, 다르게 취급된다.
  • ci(Case Insensitive) : 대소문자를 동일하게 취급한다.
    • ex) A = a

4. 핵심 차이점 요약

구분utf8mb4_0900_ai_ci (최신 표준)utf8mb4_general_ci (구버전)
정확성매우 높음. 다국어와 특수 문자를 언어 규칙에 맞게 정확하게 정렬.낮음. 단순화된 규칙을 사용해 특정 문자나 언어에서 정렬 오류가 발생할 수 있음
기반 표준Unicode 9.0.0 (UCA)구버전의 단순화된 유니코드 규칙
지원 범위악센트, 대소문자, 이모지, 특수 기호를 폭넓고 정확하게 처리기본적인 문자 처리에 중점
성능최신 CPU에 최적화되어 general_ci와 성능 차이가 거의 없음구버전 MySQL에서는 약간 더 빨랐지만, 이는 정확성을 희생한 결과
기본값MySQL 8.0 이상의 기본 정렬 규칙MySQL 8.0 미만 버전에서 널리 사용

utf8mb4_0900_ai_ci의 한글 사용에 대한 문제점

  • MySQL 8.0 이상 버전부터 기본 콜레이션으로 설정된 utf8mb4_0900_ai_ci 는 한글이나 동아시아 계열의 문자를 사용하는 나라에서는 치명적인 문제가 있다.
  • 한글의 자음 모음, 일본어 가타카나/히라가나를 같은 문자열로 인식하여 처리 하기 때문에 글로벌 서비스인 경우 콜레이션 설정을 반드시 주의해야 한다.

1. utf8mb4_general_ci 에서 한글 데이터를 조건으로 검색한 결과

mysql> select no, name, length(name), hex(name) from test1 t1
    -> where name = '가나다';
+----+-----------+--------------+--------------------+
| no | name      | length(name) | hex(name)          |
+----+-----------+--------------+--------------------+
|  1 | 가나다    |            9 | EAB080EB8298EB8BA4 |
+----+-----------+--------------+--------------------+
1 row in set (0.00 sec)

mysql> select no, name, length(name), hex(name) from test1 t1
    -> where name = 'ㄱㅏ나다';
+----+--------------+--------------+--------------------------+
| no | name         | length(name) | hex(name)                |
+----+--------------+--------------+--------------------------+
|  2 | ㄱㅏ나다     |           12 | E384B1E3858FEB8298EB8BA4 |
+----+--------------+--------------+--------------------------+
1 row in set (0.00 sec)

mysql> select no, name, length(name), hex(name) from test1 t1
    -> where name = 'ㄱㅏㄴㅏㄷㅏ';
+----+--------------------+--------------+--------------------------------------+
| no | name               | length(name) | hex(name)                            |
+----+--------------------+--------------+--------------------------------------+
|  3 | ㄱㅏㄴㅏㄷㅏ       |           18 | E384B1E3858FE384B4E3858FE384B7E3858F |
+----+--------------------+--------------+--------------------------------------+
1 row in set (0.00 sec)
  • 정확히 동일한 문자열만 조회한다.

2. utf8mb4_0900_ai_ci에서 한글 데이터를 조건으로 검색한 결과

mysql> select no, name, length(name), hex(name) from test2 t2
    -> where name = '가나다';
+----+--------------------+--------------+--------------------------------------+
| no | name               | length(name) | hex(name)                            |
+----+--------------------+--------------+--------------------------------------+
|  1 | 가나다             |            9 | EAB080EB8298EB8BA4                   |
|  2 | ㄱㅏ나다           |           12 | E384B1E3858FEB8298EB8BA4             |
|  3 | ㄱㅏㄴㅏㄷㅏ       |           18 | E384B1E3858FE384B4E3858FE384B7E3858F |
+----+--------------------+--------------+--------------------------------------+
3 rows in set (0.00 sec)

mysql> select no, name, length(name), hex(name) from test2 t2 
    -> where name = 'ㄱㅏ나다';
+----+--------------------+--------------+--------------------------------------+
| no | name               | length(name) | hex(name)                            |
+----+--------------------+--------------+--------------------------------------+
|  1 | 가나다             |            9 | EAB080EB8298EB8BA4                   |
|  2 | ㄱㅏ나다           |           12 | E384B1E3858FEB8298EB8BA4             |
|  3 | ㄱㅏㄴㅏㄷㅏ       |           18 | E384B1E3858FE384B4E3858FE384B7E3858F |
+----+--------------------+--------------+--------------------------------------+
3 rows in set (0.00 sec)

mysql> select no, name, length(name), hex(name) from test2 t2 
    -> where name = 'ㄱㅏㄴㅏㄷㅏ';
+----+--------------------+--------------+--------------------------------------+
| no | name               | length(name) | hex(name)                            |
+----+--------------------+--------------+--------------------------------------+
|  1 | 가나다             |            9 | EAB080EB8298EB8BA4                   |
|  2 | ㄱㅏ나다           |           12 | E384B1E3858FEB8298EB8BA4             |
|  3 | ㄱㅏㄴㅏㄷㅏ       |           18 | E384B1E3858FE384B4E3858FE384B7E3858F |
+----+--------------------+--------------+--------------------------------------+
3 rows in set (0.00 sec)
  • 길이나 hex 값이 다름에도, 모두 동일한 글자로 인식하고 결과값으로 모두 반환한다.

3. 후행 공백(Trailing Spaces) 처리 방식의 차이

  • 두 콜레이션은 문자열 끝에 있는 공백을 처리하는 규칙이 다르다.
    • utf8mb4_general_ci : 문자열 끝의 공백을 무시하고 비교한다. (PAD SPACE 규칙)
    • utf8mb4_0900_ai_ci : 문자열 끝의 공백을 의미 있는 다른 문자로 인식한다. (NO PAD 규칙)

3-1. general_ci: 공백을 무시하여 2개 모두 검색됨

mysql> SELECT * FROM test3 WHERE name = 'test';
+--------+
| name   |
+--------+
| test   |
| test   |
+--------+

3-2. 0900_ai_ci: 공백을 인식하여 정확히 1개만 검색됨

mysql> SELECT * FROM test4 WHERE name = 'test';
+------+
| name |
+------+
| test |
+------+

결론 : 상황별 추천 콜레이션

1. utf8mb4_0900_ai_ci

  • 다양한 언어의 텍스트를 다루는 글로벌 서비스 또는 일반적인 웹 애플리케이션을 구축할 때
  • 언어학적 규칙에 맞는 정확한 정렬이 중요할 때
  • ex) 사용자들이 MüllerMuller, cafecafé를 입력했을 때, 이를 유사한 단어로 인식하고 검색하거나 정렬해야 하는 경우

2. utf8mb4_general_ci

  • 한글 데이터가 중심이며, 완성형 글자()와 자소 분리 글자(+)를 의도적으로 다르게 취급하고 싶을 때
  • UNIQUE 키 등에서 두 형태가 명확히 구분되어야 할 때
  • 후행 공백을 무시하고 비교하고 싶을 때

3. utf8mb4_bin

  • 대소문자를 반드시 구분해야 하는 데이터일 때
  • 가장 빠르게 비교 및 정렬하고 싶을 때

4. 요약

Collation핵심 특징주요 사용 사례
utf8mb4_0900_ai_ci정확성, 국제 표준, 언어학적 규칙글로벌 서비스 또는 대부분의 현대 웹 애플리케이션 (예: cafe = café 처리가 필요할 때)
utf8mb4_general_ci단순/직관적 비교, 한글 자소 분리한글 중심 서비스에서 완성형/조합형 글자를 명확히 구분하고 싶을 때 (예: +)
utf8mb4_bin바이너리(바이트) 값 비교, 대소문자 구분API 키, 비밀번호, 인증 토큰 등 대소문자를 포함한 모든 문자를 정확히 구분해야 할 때

참고한 글

MySQL 8.0.1 utf8mb4_0900_ai_ci의 한글 사용에 대한 문제점 - RastaLion.dev