utf8_general_ci
와 utf8_unicode_ci
사이에 성능 면에서 차이가 있습니까?
utf8_general_ci와 utf8_unicode_ci의 차이점은 무엇입니까?
질문자 :KahWee Teng
2020년 또는 그 이후에 이 질문에 여전히 도달하는 사람들에게는 이 두 가지 보다 더 나은 새로운 옵션이 있습니다. 예: utf8mb4_0900_ai_ci
.
이러한 모든 데이터 정렬은 UTF-8 문자 인코딩을 위한 것입니다. 차이점은 텍스트를 정렬하고 비교하는 방법에 있습니다.
_unicode_ci
및 _general_ci
는 예상하는 방식에 따라 텍스트를 정렬하고 비교하기 위한 두 가지 다른 규칙 세트입니다. 최신 버전의 MySQL은 유니코드 9.0을 기반으로 하는 동등한 규칙에 대해 _0900_ai_ci
와 같은 새로운 규칙 세트를 도입 _general_ci
변형이 없습니다. 지금 이 글을 읽고 있는 사람들은 _unicode_ci
또는 _general_ci
대신 이러한 최신 데이터 정렬 중 하나를 사용해야 합니다. 아래의 오래된 데이터 정렬에 대한 설명은 관심을 위해서만 제공됩니다.
MySQL은 현재 결함이 있는 오래된 UTF-8 구현에서 벗어나고 있습니다. 지금은 문자 인코딩 부분에 utf8
utf8mb4
를 사용해야 고정 버전을 얻을 수 있습니다. 결함이 있는 버전은 더 이상 사용되지 않지만 이전 버전과의 호환성을 위해 남아 있습니다.
주요 차이점
utf8mb4_unicode_ci
는 범용 정렬 및 비교를 위한 공식 유니코드 규칙을 기반으로 하며 광범위한 언어에서 정확하게 정렬됩니다.utf8mb4_general_ci
는 속도 향상을 위해 설계된 많은 지름길을 사용하면서 가능한 한 잘 수행하는 것을 목표로 하는 단순화된 정렬 규칙 세트입니다. 유니코드 규칙을 따르지 않으며 특정 언어나 문자를 사용할 때와 같은 일부 상황에서 바람직하지 않은 정렬 또는 비교가 발생합니다.최신 서버에서 이러한 성능 향상은 거의 무시할 수 있습니다. 서버가 오늘날 컴퓨터의 CPU 성능의 아주 작은 부분을 차지하던 시기에 고안되었습니다.
utf8mb4_unicode_ci
보다 utf8mb4_general_ci
이점
utf8mb4_unicode_ci
는 광범위한 언어에서 그리고 광범위한 특수 문자를 사용할 때 올바른 정렬을 위해 상당히 복잡한 알고리즘을 사용합니다. 이러한 규칙은 언어별 규칙을 고려해야 합니다. 모든 사람이 우리가 '알파벳 순서'라고 부르는 대로 문자를 정렬하는 것은 아닙니다.
라틴어(예: "유럽") 언어 utf8mb4_general_ci
정렬 사이에는 큰 차이가 없지만 여전히 몇 가지 차이점이 있습니다.
예를 들어, 유니코드 데이터 정렬은 "ß"를 "ss"와 같이 정렬하고 "Œ"를 "OE"와 같이 해당 문자를 사용하는 사람들이 일반적으로 원하는
utf8mb4_general_ci
정렬하는 반면 utf8mb4_general_ci는 단일 문자로 정렬합니다(각각 "s" 및 "e"와 같이). ).일부 유니코드 문자는 무시할 수 있는 것으로 정의됩니다. 즉, 정렬 순서에 포함되어서는 안 되며 비교는 대신 다음 문자로 이동해야 합니다.
utf8mb4_unicode_ci
는 이를 적절하게 처리합니다.
아시아 언어나 알파벳이 다른 언어와 같은 비라틴어에서는 유니코드 정렬과 단순화된 utf8mb4_general_ci
정렬 사이에 훨씬 더 많은 차이가 있을 수 있습니다. utf8mb4_general_ci
의 적합성은 사용된 언어에 크게 의존합니다. 일부 언어의 경우 상당히 부적절합니다.
무엇을 사용해야합니까?
성능 차이가 중요할 정도로 CPU 속도가 충분히 낮은 지점을 남겨 utf8mb4_general_ci
때문에 더 이상 utf8mb4_general_ci를 사용할 이유가 거의 없습니다. 데이터베이스는 이것 이외의 다른 병목 현상으로 인해 거의 확실히 제한될 것입니다.
과거에는 성능 비용을 정당화할 만큼 정확한 정렬이 중요할 때를 제외하고 utf8mb4_general_ci
를 사용하는 것이 좋습니다. 오늘날 그 성능 비용은 거의 사라졌고 개발자들은 국제화를 더욱 심각하게 다루고 있습니다.
정확성보다 속도가 더 중요하다면 정렬을 전혀 하지 않는 편이 낫다는 주장이 있습니다. 정확할 필요가 없다면 알고리즘을 더 빠르게 만드는 것은 사소한 일입니다. 따라서 utf8mb4_general_ci
는 속도상의 이유로 필요하지 않을 수도 있고 정확도상의 이유로 적합하지 않을 수도 있는 절충안입니다.
내가 추가할 또 한 가지는 응용 프로그램이 영어만 지원한다는 것을 알고 있더라도 여전히 사람들의 이름을 처리해야 할 수 있다는 것입니다. . 모든 것에 유니코드 규칙을 사용하면 매우 똑똑한 유니코드 사람들이 정렬이 제대로 작동하도록 매우 열심히 일했다는 마음의 평화를 얻는 데 도움이 됩니다.
부품의 의미
첫째, ci
는 대소문자를 구분하지 않는 정렬 및 비교를 위한 것입니다. 즉, 텍스트 데이터에 적합하며 대소문자는 중요하지 않습니다. 다른 유형의 데이터 정렬은 대소문자가 중요한 텍스트 데이터의 경우 cs
bin
은 실제로 인코딩된 이진 데이터(예: 예: Base64). 대소문자를 구분하는 정렬은 이상한 결과를 낳고 대소문자를 구분하는 비교는 중복된 값이 대소문자만 다를 수 있으므로 대소문자를 구분하는 데이터 정렬이 텍스트 데이터에 적합하지 않습니다. 대소문자가 중요한 경우 구두점을 무시할 수 있습니다. 등도 중요할 수 있으며 이진 데이터 정렬이 더 적절할 수 있습니다.
다음으로 unicode
또는 general
은 특정 정렬 및 비교 규칙, 특히 텍스트가 정규화되거나 비교되는 방식을 나타냅니다. utf8mb4 문자 인코딩에는 다양한 규칙 세트가 있으며, unicode
와 general
은 하나의 특정 언어가 아닌 모든 가능한 언어에서 잘 작동하도록 시도하는 두 가지입니다. 이 두 가지 규칙 집합 간의 차이점이 이 답변의 주제입니다. unicode
는 유니코드 4.0의 규칙을 사용합니다. 최신 버전의 MySQL은 유니코드 5.2의 규칙을 사용하여 unicode_520
0900
("unicode_" 부분 삭제)을 추가합니다.
그리고 마지막으로 utf8mb4
는 물론 내부적으로 사용되는 문자 인코딩입니다. 이 답변에서는 유니코드 기반 인코딩에 대해서만 이야기하고 있습니다.
thomasrutter
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
SELECT
, SELECT
와 LIKE
및 정렬( SELECT
와 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번( utf8_general_ci
5번, utf8_unicode_ci
5번) 호출한 다음 평균 값을 계산했습니다.
내 결과는 다음과 같습니다.
benchmark_simple_select()
-
utf8_general_ci
: 9,957ms -
utf8_unicode_ci
: 10,271ms
이 벤치마크에서 utf8_unicode_ci
utf8_general_ci
보다 3.2% 느립니다.
benchmark_select_like()
-
utf8_general_ci
: 11,441ms -
utf8_unicode_ci
: 12,811ms
이 벤치마크에서 utf8_unicode_ci
utf8_general_ci
보다 12% 느립니다.
benchmark_order_by()
-
utf8_general_ci
: 11,944ms -
utf8_unicode_ci
: 12,887ms
이 벤치마크에서 utf8_unicode_ci
utf8_general_ci
보다 7.9% 느립니다.
nightcoder
이 게시물 은 매우 친절하게 설명합니다.
간단히 말해서: utf8_unicode_ci
는 유니코드 표준에 정의된 대로 유니코드 데이터 정렬 알고리즘을 사용하는 반면 utf8_general_ci
는 "덜 정확한" 정렬 결과를 초래하는 보다 단순한 정렬 순서입니다.
Michael Madsen
mysql 매뉴얼의 Unicode Character Sets 섹션을 참조하십시오.
모든 유니코드 문자 집합의 경우 _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 세트는 수행할 계산이 적기 때문에 더 빠릅니다.
Dana the Sane
간단히 말해서:
더 나은 정렬 순서가 필요한 경우 - utf8_unicode_ci
사용하십시오(이것이 선호되는 방법입니다).
그러나 성능에 완전히 관심이 있다면 utf8_general_ci
사용하지만 약간 구식이라는 것을 알고 있습니다.
성능면에서 차이는 매우 미미합니다.
simhumileco
일부 세부정보(PL)
여기에서 읽을 수 있듯이( Peter Gulutzan ) 폴란드어 문자 "Ł"(획이 있는 L - html esc: Ł
)(소문자: "ł" - 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
앞에 있습니다. 이 코딩 중 어느 것도 더 낫거나 더 나쁠 수 없습니다. 사용자의 필요에 따라 다릅니다.
Kamil Kiełczewski
정렬과 문자 일치에는 두 가지 큰 차이점이 있습니다.
정렬 :
-
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=ª
및 ß=ss
의 utf8mb4_unicode_ci
의 경우가 아니라 utf8mb4_general_ci
. name="ªßi"
인 행이 있다고 상상해 보십시오. 그런 다음
select id from users where name='assi';
배열이있는 경우 행을 반환 utf8mb4_unicode_ci
하지만 배열이 설정되어있는 경우 행을 반환하지 않을 utf8mb4_general_ci
.
각 배열에 대한 전체 일치 목록은 여기 에서 찾을 수 있습니다.
Adam
이 게시물에 따르면 utf8mb4_unicode_ci 대신 utf8mb4_general_ci를 사용할 때 MySQL 5.7에서 상당히 큰 성능 이점이 있습니다. https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql 성능/
DavidH
출처 : http:www.stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci