utf8_general_ci와 utf8_unicode_ci의 차이점은 무엇입니까?


1063

utf8_general_ci와 사이 utf8_unicode_ci에 성능 측면에서 차이가 있습니까?



6
당신이 좋아한다면 utf8[mb4]_unicode_ci, 당신 utf8[mb4]_unicode_520_ci 훨씬 더 좋아할 것입니다.
Rick James

8
나는 그것에 대해 어떻게 생각하는지 모르겠다. 최신 유니 코드 표준을 따르도록 구현을 수정하는 대신 쓸모없는 버전을 기본값으로 유지하고 사람들은 "520"을 추가하여 적절한 버전을 사용한다. 그리고 이전 MySQL 버전에서는 "520"버전을 사용할 수 없기 때문에 앞뒤로 호환되지 않습니다. 기존 데이터 정렬을 업데이트 할 수없는 이유는 무엇입니까? "mb4"와 동일합니다. 어떤 코드가 이전의 제한적이거나 쓸모없는 동작에 의존하여 기본 설정으로 유지 했습니까?
thomasrutter

7
8.0의 기본값이 더 좋습니다 utf8mb4_0900_ai_ci.
Rick James

답변:


1591

이 두 데이터 정렬은 모두 UTF-8 문자 인코딩을위한 것입니다. 차이점은 텍스트를 정렬하고 비교하는 방법에 있습니다.

참고 : MySQL에서는을 사용 utf8mb4하지 않아야 utf8합니다. 혼란스럽게도 utf8초기 MySQL 버전의 결함이있는 UTF-8 구현은 이전 버전과의 호환성을 위해서만 남아 있습니다. 고정 버전의 이름이 지정되었습니다 utf8mb4.

참고 : 최신 버전의 MySQL은 utf8mb4_0900_ai_ci 유니 코드 9.0을 기반 으로 하는 동등한 규칙 과 같은 이름으로 사용 가능한 등가 _general 변형 없이 유니 코드 정렬 규칙을 업데이트했습니다 . 이 글을 읽는 사람들은 아마도 _unicode 또는 대신에이 새로운 콜 레이션 중 하나를 사용해야 할 것입니다_general . 새로운 콜 레이션 중 하나를 대신 사용할 수 있다면 아래에 쓰여진 대부분의 내용은 더 이상 관심이 없습니다.

주요 차이점

  • utf8mb4_unicode_ci 범용 정렬 및 비교에 대한 공식 유니 코드 규칙을 기반으로하며 광범위한 언어로 정확하게 정렬됩니다.

  • utf8mb4_general_ci는 속도를 높이기 위해 설계된 많은 단축키를 사용하면서 할 수있을뿐만 아니라 할 수있는 단순한 정렬 규칙 세트입니다. 유니 코드 규칙을 따르지 않으며 특정 언어 나 문자를 사용할 때와 같은 일부 상황에서는 원하지 않는 정렬이나 비교가 발생합니다.

    최신 서버에서이 성능 향상은 무시할 수 없을 것입니다. 서버가 오늘날 컴퓨터의 CPU 성능의 작은 부분을 차지할 때 고안되었습니다.

utf8mb4_unicode_ci이상의 장점utf8mb4_general_ci

utf8mb4_unicode_ci정렬 및 비교에 유니 코드 규칙을 사용하는에는 광범위한 언어 및 광범위한 특수 문자를 사용할 때 올바른 정렬을 위해 상당히 복잡한 알고리즘을 사용합니다. 이러한 규칙은 언어 별 규칙을 고려해야합니다. 모두가 우리가 '알파벳 순서'라고 부르는 방식으로 문자를 정렬하는 것은 아닙니다.

라틴어 (예 : "유럽어") 언어에 관한 한, utf8mb4_general_ciMySQL 의 유니 코드 정렬과 단순화 된 정렬 사이에는 큰 차이가 없지만 몇 가지 차이점이 있습니다.

  • 예를 들어, 유니 코드 데이터 정렬은 "ss"와 같이 "ß"를 정렬하고 "OE"와 같이 "Œ"를 utf8mb4_general_ci정렬합니다 (예 : "s"및 "e"와 같은 단일 문자로 정렬). .

  • 일부 유니 코드 문자는 무시할 수있는 것으로 정의되므로 정렬 순서에 포함되지 않으며 비교는 다음 문자로 넘어갑니다. utf8mb4_unicode_ci이것들을 올바르게 처리합니다.

아시아 언어 또는 알파벳이 다른 언어와 같은 비 라틴 언어의 경우 유니 코드 정렬과 단순화 된 정렬 간에 더 많은 차이 가있을 수 있습니다 utf8mb4_general_ci. 의의 적합성은 utf8mb4_general_ci사용되는 언어에 크게 의존합니다. 일부 언어의 경우 상당히 부적절합니다.

무엇을 사용해야합니까?

utf8mb4_general_ciCPU 속도가 느려 성능 차이가 중요 할 정도로 뒤쳐 졌기 때문에 더 이상 사용할 이유가 거의 없습니다 . 데이터베이스는 이것 이외의 다른 병목 현상에 의해 거의 확실하게 제한됩니다.

과거에는 일부 사람들이 utf8mb4_general_ci정확한 정렬이 성능 비용을 정당화하기에 충분히 중요 할 때를 제외하고 는 사용을 권장했습니다 . 오늘날 그 성능 비용은 거의 사라졌고 개발자들은 국제화를 더욱 심각하게 다루고 있습니다.

정확성보다 속도가 더 중요하다면 어떤 정렬도하지 않을 수 있다는 주장이 있습니다. 알고리즘이 정확하지 않아도 더 빠른 알고리즘을 만드는 것은 쉽지 않습니다. 따라서 utf8mb4_general_ci속도 때문에 필요하지 않을 수도 있고 정확도 때문에 적합하지 않은 타협입니다.

내가 추가해야 할 또 다른 사항은 응용 프로그램이 영어 만 지원한다는 것을 알고 있더라도 사람들의 이름을 처리해야 할 수도 있습니다.이 이름은 종종 올바르게 정렬하는 것만 큼 중요한 다른 언어로 사용되는 문자를 포함 할 수 있습니다 . 모든 것에 유니 코드 규칙을 사용하면 매우 똑똑한 유니 코드 사람들이 정렬 작업을 제대로 수행하기 위해 매우 열심히 노력했음을 안심할 수 있습니다.

부품의 의미

첫째, ci입니다 대소 문자를 구분하지 정렬 및 비교. 이는 텍스트 데이터에 적합하고 대소 문자는 중요하지 않음을 의미합니다. 다른 유형의 데이터 정렬은 대 cs/ 소문자를 구분 bin해야하는 텍스트 데이터 및 (대 / 소문자 구분) 인코딩이 일치해야하는 경우 비트 단위로, 실제로 이진 데이터로 인코딩 된 필드 (예 : Base64). 대소 문자 구분 정렬은 약간의 이상한 결과를 초래하고 대소 문자 구분 비교는 대소 문자 만 다른 중복 값을 초래할 수 있으므로 대소 문자 구분 데이터 정렬은 텍스트 데이터에 적합하지 않습니다. 대소 문자가 중요하면 무시할 수없는 문장 부호입니다. 등도 중요 할 수 있으며 이진 데이터 정렬이 더 적합 할 수 있습니다.

다음으로 unicode또는 general특정 정렬 및 비교 규칙, 특히 텍스트가 정규화되거나 비교되는 방식을 나타냅니다. 거기 utf8mb4 문자 인코딩에 대한 규칙의 많은 다른 세트와 함께입니다 unicodegeneral이되는 것을 잘 가능한 모든 언어로 작업을 시도하기보다는 하나의 특정의 하나. 이 두 규칙 세트의 차이점이이 답변의 주제입니다. unicode유니 코드 4.0의 규칙 을 사용합니다. 최신 버전의 MySQL unicode_520은 유니 코드 5.2 의 규칙을 사용하여 규칙 세트 를 추가하고 0900유니 코드 9.0의 규칙을 사용하여 "unicode_"부분을 삭제합니다.

그리고 마지막으로, utf8mb4내부적으로 사용되는 문자 인코딩입니다. 이 답변에서는 유니 코드 기반 인코딩에 대해서만 이야기하고 있습니다.


218
@KahWeeTeng 당신이해야 결코, 이제까지 사용 utf8_general_ci: 그것은 단순히 작동하지 않습니다. 그것은 50 년 전의 ASCII stooopeeedity의 나쁜 시절로 되돌아 간 것입니다. UCD의 폴드 케이스 맵이 없으면 유니 코드 대소 문자 구분없이 일치를 수행 할 수 없습니다. 예를 들어 "Σίσυφος"에는 세 가지 시그마가 있습니다. 또는 "TSCHüẞ"의 소문자가 "tschüβ"이지만 "tschüβ"의 대문자는 "TSCHÜSS"입니다. 당신은 옳거나 빠를 수 있습니다. 따라서 utf8_unicode_ci정확성에 신경 쓰지 않는다면 무한히 빨리 만드는 것이 쉽지 않기 때문에를 사용해야합니다 .
tchrist

7
이것을 읽은 후 나는 또한 utf8_unicode_ci가 평등 비교를 위해 데이터 정렬 가중치가 동일한 문자를 동일한 것으로 간주한다는 것을 알았습니다. 이 경우에 이르게 "か" == "が"하거나 "ǽ" == "æ". 정렬을 위해 이것은 의미가 있지만 평등을 통해 선택하거나 고유 색인을 처리 할 때 놀랍습니다 -bugs.mysql.com/bug.php?id=16526
Mat Schaffer

4
@DanHorvat MySQL의 더 오래되고 제한적인 유니 코드 하위 집합으로 자신을 제한하는 유일한 실질적인 이유는보다 완전한 utf8mb4를 지원하지 않는 이전 버전의 MySQL이있는 경우입니다. 5.5.3은 5 세 이상입니다. Plesk는 다른 MySQL 일정으로 실행되지만 대부분의 배포판은 현재 MySQL 5.5에 있으며 Plesk 11.x 구성 요소를 업데이트하면 MySQL 5.5를 지원합니다.
thomasrutter

22
더 새롭고 더 표준에 맞는 변형을 사용하는 것은 나쁜 습관이라고 생각하지 않으며, 나쁜 개발자들을 이런 식으로 사람들에게 부르는 것이 염증 적이라고 생각합니다. 내 대답은 " 새로운 버전 의 MySQL에서는 utf8이 아닌 utf8mb4를 사용합니다"라고 강조합니다.
thomasrutter

23
@DanHorvat utf8mb4유일한 올바른 선택 입니다. 으로 utf8당신이 UTF8의 일부 MySQL의 전용, 3 바이트 변형에 붙어 만 MySQL을 (그리고 MariaDB)가 수행 할 작업을 알고있다. 세계의 다른 지역은 문자 당 최대 4 바이트를 포함 수있는 UTF8을 사용하고 있습니다 . MySQL 개발자는 homebrew 인코딩의 이름을 잘못 지정하고 utf8이전 버전과의 호환성을 유지하지 않기 위해 실제 UTF8을로 참조해야합니다 utf8mb4.
Stijn de Witt

162

사용 utf8_general_ci과 의 성능 차이가 무엇인지 알고 싶었지만 utf8_unicode_ci인터넷에 나열된 벤치 마크를 찾지 못했기 때문에 벤치 마크를 직접 작성하기로 결정했습니다.

500,000 행으로 매우 간단한 테이블을 만들었습니다.

CREATE TABLE test(
  ID INT(11) DEFAULT NULL,
  Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

그런 다음이 저장 프로 시저를 실행하여 임의의 데이터로 채웠습니다.

CREATE PROCEDURE randomizer()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE random CHAR(20) ;
  theloop: loop
    SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
    INSERT INTO test VALUES (i+1, random);
    SET i=i+1;
    IF i = 500000 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END

그런 다음 simple SELECT, SELECTwith LIKE및 sorting ( SELECTwith ORDER BY) 을 벤치마킹하기 위해 다음 저장 프로 시저를 작성했습니다 .

CREATE PROCEDURE benchmark_simple_select()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description = 'test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_select_like()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description LIKE '%test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_order_by()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
    ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
    SET i = i + 1;
    IF i = 10 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

위의 저장 프로 시저에서는 utf8_general_ci데이터 정렬이 사용되지만 테스트 중에는 utf8_general_ci및을 모두 사용했습니다 utf8_unicode_ci.

나는 (5 회 저장 프로 시저 각 조합에 대한 5 회 호출 utf8_general_ci과 5 회 utf8_unicode_ci) 한 후 평균값을 계산 하였다.

내 결과는 다음과 같습니다

benchmark_simple_select()

  • utf8_general_ci: 9957 MS
  • utf8_unicode_ci: 10,271 ms

이 벤치 마크에서는 utf8_unicode_ci사용률이 utf8_general_ci3.2 % 보다 느립니다 .

benchmark_select_like()

  • utf8_general_ci: 11,441 ms
  • utf8_unicode_ci: 12,811 ms

이 벤치 마크에서는 utf8_unicode_ci사용률이 utf8_general_ci12 % 보다 느립니다 .

benchmark_order_by()

  • utf8_general_ci: 11,944 ms
  • utf8_unicode_ci: 12,887 ms

이 벤치 마크에서는 사용률이 7.9 % utf8_unicode_ci보다 느립니다 utf8_general_ci.


16
공유해 주셔서 감사합니다. 상당히 비슷한 수치 (Windows의 MySQL v5.6.12)가 10 %, 4 %, 8 %입니다. 나는 동의한다. 성능 utf8_general_ci이 너무 작아서 사용할 가치가 없다.
RandomSeed

10
1) 그러나이 벤치 마크가 정의에 따라 두 데이터 정렬에 대해 유사한 결과를 생성해서는 안됩니까? CONV(FLOOR(RAND() * 99999999999999), 20, 36)데이터 정렬 알고리즘으로 처리 할 ASCII 만 생성하고 유니 코드 문자 는 생성하지 않습니다. 2) Description = 'test' COLLATE ...Description LIKE 'test%' COLLATE ...그들 만이 런타임에 하나의 문자열 ( "테스트")하지 않는 처리? 3) 실제 앱에서는 순서에 사용 된 열이 색인화 될 수 있으며 실제 비 ASCII 텍스트를 사용하는 다른 데이터 정렬의 색인화 속도가 다를 수 있습니다.
Halil Özgür

2
@ HalilÖzgür-요점이 부분적으로 잘못되었습니다. 코드 포인트 값이 ASCII 외부 (일반 _ci가 올바르게 처리 할 수 ​​있음)가 아니라 "Uml ea ute" 로 작성된 움라우트 또는 그러한 미묘한 부분을 처리하는 것과 같은 특정 기능에 관한 것 같습니다 .
Tomasz Gandor

38

이 게시물 은 그것을 아주 잘 설명합니다.

요약하자면, utf8_unicode_ci는 유니 코드 표준에 정의 된대로 Unicode Collation Algorithm을 사용하는 반면, utf8_general_ci는 "정확하지 않은"정렬 결과를 만드는보다 간단한 정렬 순서입니다.


1
감사. 그건 내 인상이었습니다. 나는 성능 히트를 취할 것이다 :)
onassar

7
정확성에 신경 쓰지 않는다면 알고리즘을 무한히 빨리 만드는 것이 쉽지 않습니다. utf8_unicode_ci존재하지 않는 다른 것을 사용 하고 가장하십시오.
tchrist

1
@tchrist 그러나 정확성과 속도의 특정 균형에 관심이 있다면 당신을 utf8_general_ci위한 것일 수도 있습니다
Shelvacu

@tchrist 게임 프로그래머가되지 마십시오)
스테인 드 위트

1
@onassar-MySQL 8.0 은 모든 데이터 정렬의 성능 이 크게 향상 되었다고 주장합니다 .
Rick James

9

mysql 매뉴얼, Unicode 문자 세트 섹션을 참조하십시오 :

유니 코드 문자 집합의 경우 _general_ci 데이터 정렬을 사용하여 수행 된 작업은 _unicode_ci 데이터 정렬보다 빠릅니다. 예를 들어, utf8_general_ci 데이터 정렬에 대한 비교는 utf8_unicode_ci에 대한 비교보다 빠르지 만 약간 덜 정확합니다. 그 이유는 utf8_unicode_ci가 확장과 같은 맵핑을 지원하기 때문입니다. 즉, 한 문자가 다른 문자의 조합과 같을 때. 예를 들어 독일어 및 일부 다른 언어에서 "ß"는 "ss"와 같습니다. utf8_unicode_ci는 수축 및 무시할 수있는 문자도 지원합니다. utf8_general_ci는 확장, 축소 또는 무시할 수없는 문자를 지원하지 않는 레거시 데이터 정렬입니다. 문자를 일대일로 비교할 수 있습니다.

요약하자면, utf_general_ci는 전체 표준을 구현 해야하는 utf_unicode_ci보다 더 작고 덜 정확한 (표준에 따름) 비교 세트를 사용 합니다 . 계산이 적기 때문에 general_ci 세트가 더 빠릅니다.


18
“약간 덜 정확한”것은 없습니다. 정확성은 부울 특성입니다. 정도 수정자를 허용하지 않습니다. utf8_unicode_ci버그가있는 깨진 버전이 존재하지 않는 것을 사용 하고 가장하십시오.
tchrist

2
collation_connection 설정을 가져 오기 위해 5.6.15를 얻는 데 문제가 있었고 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci'와 같은 SET 줄에 전달해야합니다. 크레디트는 솔루션으로 Mathias Bynens에게 갔다. 그의 유용한 가이드는 다음과 같다
Steve Hibbert

4
@tchrist 정확성이 부울이라고 말하는 문제는 절대적 정확성에 의존하지 않는 상황을 고려하지 않는다는 것입니다. 귀하의 기본 요지가 유효하지 않거나 general_ci의 이점을 배우려고하지는 않지만 정확성에 대한 일반적인 진술은 쉽게 반증되지 않습니다. 나는 직업에서 매일 그것을한다. 코미디를 제외하고 스튜어트는 여기에 좋은 지적이 있다 .
Anthony

5
지리적 위치 또는 게임 개발을 통해 우리는 항상 정확성과 정확성을 교환합니다. 물론 정확성은 실제 사이의 숫자 01,되지 부울. :) 경계 상자에서 EG 선택 지리적 지점은 '근처 지점'의 근사값으로, 지점과 기준점 사이의 거리를 계산하고 필터링하는 것만 큼 좋지 않습니다. 그러나 둘 다 근사치이며 실제로 완전한 정확성은 대부분 달성 할 수 없습니다.
Stijn de Witt

4
TL; DR :에 대한 정확한 결과를 인쇄하는 프로그램을 제공하십시오1/3
Stijn de Witt

7

간단히 말해서 :

더 나은 정렬 순서가 필요한 경우 사용하십시오 utf8_unicode_ci(이 방법이 선호 됨).

그러나 성능 사용에 전적으로 관심이 utf8_general_ci있지만 약간 오래되었다는 것을 알고 있습니다.

성능 측면에서의 차이는 매우 작습니다.


1
둘 다 이제 구식입니다. 더 많은 답변보기
thomasrutter

감사합니다. @thomasrutter
simhumileco

6

일부 세부 사항 (PL)

여기서 읽을 수 있듯이 ( Peter Gulutzan ) 폴란드어 문자 "Ł"(획-html esc : L Ł) (소문자 : "ł"-html esc :) 정렬 / 비교에 차이 ł가 있습니다.

utf8_polish_ci      Ł greater than L and less than M
utf8_unicode_ci     Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci     Ł greater than Z

폴란드어로 된 편지 Ł는 편지 뒤 L와 앞 M입니다. 이 코딩 중 어느 것도 더 나쁘지 않습니다. 필요에 따라 다릅니다.


1

정렬과 문자 일치에는 두 가지 큰 차이가 있습니다.

정렬 :

  • utf8mb4_general_ci 모든 악센트를 제거하고 잘못된 정렬 결과를 생성 할 수있는 하나씩 정렬합니다.
  • utf8mb4_unicode_ci 정확하게 정렬합니다.

문자 매칭

문자가 다르게 일치합니다.

예를 들어, utf8mb4_unicode_ci당신은 i != ı있지만 utf8mb4_general_ci보유하고 있습니다 ı=i.

예를 들어와 행이 있다고 가정합니다 name="Yılmaz". 그때

select id from users where name='Yilmaz';

배열이있는 경우 행을 반환 utf8mb4_general_ci하지만이 함께 배치되어있는 경우 utf8mb4_unicode_ci그 것 없는 행을 반환!

우리가 가지고있는 반면에 a=ªß=ssutf8mb4_unicode_ci있는 경우가 아니다 utf8mb4_general_ci. 그래서 당신이 가진 행이 상상 name="ªßi"한 후,

select id from users where name='assi';

배열이 utf8mb4_unicode_ci이면 행을 반환 하지만 배열이로 설정되어 있으면 행을 반환 하지 않습니다utf8mb4_general_ci .

각 배열에 대한 전체 일치 목록은 여기 에서 찾을 수 있습니다 .


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.