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

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



답변

이 두 데이터 정렬은 모두 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내부적으로 사용되는 문자 인코딩입니다. 이 답변에서는 유니 코드 기반 인코딩에 대해서만 이야기하고 있습니다.


답변

사용 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.


답변

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

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


답변

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 세트가 더 빠릅니다.


답변

간단히 말해서 :

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

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

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


답변

일부 세부 사항 (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입니다. 이 코딩 중 어느 것도 더 나쁘지 않습니다. 필요에 따라 다릅니다.


답변

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

정렬 :

  • 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 .

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