utf8_general_ci
와 사이 utf8_unicode_ci
에 성능 측면에서 차이가 있습니까?
utf8[mb4]_unicode_ci
, 당신 은utf8[mb4]_unicode_520_ci
훨씬 더 좋아할 것입니다.
utf8mb4_0900_ai_ci
.
utf8_general_ci
와 사이 utf8_unicode_ci
에 성능 측면에서 차이가 있습니까?
utf8[mb4]_unicode_ci
, 당신 은utf8[mb4]_unicode_520_ci
훨씬 더 좋아할 것입니다.
utf8mb4_0900_ai_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_ci
MySQL 의 유니 코드 정렬과 단순화 된 정렬 사이에는 큰 차이가 없지만 몇 가지 차이점이 있습니다.
예를 들어, 유니 코드 데이터 정렬은 "ss"와 같이 "ß"를 정렬하고 "OE"와 같이 "Œ"를 utf8mb4_general_ci
정렬합니다 (예 : "s"및 "e"와 같은 단일 문자로 정렬). .
일부 유니 코드 문자는 무시할 수있는 것으로 정의되므로 정렬 순서에 포함되지 않으며 비교는 다음 문자로 넘어갑니다. utf8mb4_unicode_ci
이것들을 올바르게 처리합니다.
아시아 언어 또는 알파벳이 다른 언어와 같은 비 라틴 언어의 경우 유니 코드 정렬과 단순화 된 정렬 간에 더 많은 차이 가있을 수 있습니다 utf8mb4_general_ci
. 의의 적합성은 utf8mb4_general_ci
사용되는 언어에 크게 의존합니다. 일부 언어의 경우 상당히 부적절합니다.
무엇을 사용해야합니까?
utf8mb4_general_ci
CPU 속도가 느려 성능 차이가 중요 할 정도로 뒤쳐 졌기 때문에 더 이상 사용할 이유가 거의 없습니다 . 데이터베이스는 이것 이외의 다른 병목 현상에 의해 거의 확실하게 제한됩니다.
과거에는 일부 사람들이 utf8mb4_general_ci
정확한 정렬이 성능 비용을 정당화하기에 충분히 중요 할 때를 제외하고 는 사용을 권장했습니다 . 오늘날 그 성능 비용은 거의 사라졌고 개발자들은 국제화를 더욱 심각하게 다루고 있습니다.
정확성보다 속도가 더 중요하다면 어떤 정렬도하지 않을 수 있다는 주장이 있습니다. 알고리즘이 정확하지 않아도 더 빠른 알고리즘을 만드는 것은 쉽지 않습니다. 따라서 utf8mb4_general_ci
속도 때문에 필요하지 않을 수도 있고 정확도 때문에 적합하지 않은 타협입니다.
내가 추가해야 할 또 다른 사항은 응용 프로그램이 영어 만 지원한다는 것을 알고 있더라도 사람들의 이름을 처리해야 할 수도 있습니다.이 이름은 종종 올바르게 정렬하는 것만 큼 중요한 다른 언어로 사용되는 문자를 포함 할 수 있습니다 . 모든 것에 유니 코드 규칙을 사용하면 매우 똑똑한 유니 코드 사람들이 정렬 작업을 제대로 수행하기 위해 매우 열심히 노력했음을 안심할 수 있습니다.
부품의 의미
첫째, ci
입니다 대소 문자를 구분하지 정렬 및 비교. 이는 텍스트 데이터에 적합하고 대소 문자는 중요하지 않음을 의미합니다. 다른 유형의 데이터 정렬은 대 cs
/ 소문자를 구분 bin
해야하는 텍스트 데이터 및 (대 / 소문자 구분) 인코딩이 일치해야하는 경우 비트 단위로, 실제로 이진 데이터로 인코딩 된 필드 (예 : Base64). 대소 문자 구분 정렬은 약간의 이상한 결과를 초래하고 대소 문자 구분 비교는 대소 문자 만 다른 중복 값을 초래할 수 있으므로 대소 문자 구분 데이터 정렬은 텍스트 데이터에 적합하지 않습니다. 대소 문자가 중요하면 무시할 수없는 문장 부호입니다. 등도 중요 할 수 있으며 이진 데이터 정렬이 더 적합 할 수 있습니다.
다음으로 unicode
또는 general
특정 정렬 및 비교 규칙, 특히 텍스트가 정규화되거나 비교되는 방식을 나타냅니다. 거기 utf8mb4 문자 인코딩에 대한 규칙의 많은 다른 세트와 함께입니다 unicode
및 general
이되는 것을 잘 가능한 모든 언어로 작업을 시도하기보다는 하나의 특정의 하나. 이 두 규칙 세트의 차이점이이 답변의 주제입니다. unicode
유니 코드 4.0의 규칙 을 사용합니다. 최신 버전의 MySQL unicode_520
은 유니 코드 5.2 의 규칙을 사용하여 규칙 세트 를 추가하고 0900
유니 코드 9.0의 규칙을 사용하여 "unicode_"부분을 삭제합니다.
그리고 마지막으로, utf8mb4
내부적으로 사용되는 문자 인코딩입니다. 이 답변에서는 유니 코드 기반 인코딩에 대해서만 이야기하고 있습니다.
utf8_general_ci
: 그것은 단순히 작동하지 않습니다. 그것은 50 년 전의 ASCII stooopeeedity의 나쁜 시절로 되돌아 간 것입니다. UCD의 폴드 케이스 맵이 없으면 유니 코드 대소 문자 구분없이 일치를 수행 할 수 없습니다. 예를 들어 "Σίσυφος"에는 세 가지 시그마가 있습니다. 또는 "TSCHüẞ"의 소문자가 "tschüβ"이지만 "tschüβ"의 대문자는 "TSCHÜSS"입니다. 당신은 옳거나 빠를 수 있습니다. 따라서 utf8_unicode_ci
정확성에 신경 쓰지 않는다면 무한히 빨리 만드는 것이 쉽지 않기 때문에를 사용해야합니다 .
"か" == "が"
하거나 "ǽ" == "æ"
. 정렬을 위해 이것은 의미가 있지만 평등을 통해 선택하거나 고유 색인을 처리 할 때 놀랍습니다 -bugs.mysql.com/bug.php?id=16526
utf8mb4
가 유일한 올바른 선택 입니다. 으로 utf8
당신이 UTF8의 일부 MySQL의 전용, 3 바이트 변형에 붙어 만 MySQL을 (그리고 MariaDB)가 수행 할 작업을 알고있다. 세계의 다른 지역은 문자 당 최대 4 바이트를 포함 할 수있는 UTF8을 사용하고 있습니다 . MySQL 개발자는 homebrew 인코딩의 이름을 잘못 지정하고 utf8
이전 버전과의 호환성을 유지하지 않기 위해 실제 UTF8을로 참조해야합니다 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
, SELECT
with LIKE
및 sorting ( SELECT
with 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_ci
3.2 % 보다 느립니다 .
benchmark_select_like()
utf8_general_ci
: 11,441 ms utf8_unicode_ci
: 12,811 ms 이 벤치 마크에서는 utf8_unicode_ci
사용률이 utf8_general_ci
12 % 보다 느립니다 .
benchmark_order_by()
utf8_general_ci
: 11,944 ms utf8_unicode_ci
: 12,887 ms 이 벤치 마크에서는 사용률이 7.9 % utf8_unicode_ci
보다 느립니다 utf8_general_ci
.
utf8_general_ci
이 너무 작아서 사용할 가치가 없다.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
데이터 정렬 알고리즘으로 처리 할 ASCII 만 생성하고 유니 코드 문자 는 생성하지 않습니다. 2) Description = 'test' COLLATE ...
와 Description LIKE 'test%' COLLATE ...
그들 만이 런타임에 하나의 문자열 ( "테스트")하지 않는 처리? 3) 실제 앱에서는 순서에 사용 된 열이 색인화 될 수 있으며 실제 비 ASCII 텍스트를 사용하는 다른 데이터 정렬의 색인화 속도가 다를 수 있습니다.
이 게시물 은 그것을 아주 잘 설명합니다.
요약하자면, utf8_unicode_ci는 유니 코드 표준에 정의 된대로 Unicode Collation Algorithm을 사용하는 반면, utf8_general_ci는 "정확하지 않은"정렬 결과를 만드는보다 간단한 정렬 순서입니다.
utf8_unicode_ci
존재하지 않는 다른 것을 사용 하고 가장하십시오.
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
버그가있는 깨진 버전이 존재하지 않는 것을 사용 하고 가장하십시오.
0
와 1
,되지 부울. :) 경계 상자에서 EG 선택 지리적 지점은 '근처 지점'의 근사값으로, 지점과 기준점 사이의 거리를 계산하고 필터링하는 것만 큼 좋지 않습니다. 그러나 둘 다 근사치이며 실제로 완전한 정확성은 대부분 달성 할 수 없습니다.
1/3
간단히 말해서 :
더 나은 정렬 순서가 필요한 경우 사용하십시오 utf8_unicode_ci
(이 방법이 선호 됨).
그러나 성능 사용에 전적으로 관심이 utf8_general_ci
있지만 약간 오래되었다는 것을 알고 있습니다.
성능 측면에서의 차이는 매우 작습니다.
여기서 읽을 수 있듯이 ( 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=ª
와 ß=ss
에 utf8mb4_unicode_ci
있는 경우가 아니다 utf8mb4_general_ci
. 그래서 당신이 가진 행이 상상 name="ªßi"
한 후,
select id from users where name='assi';
배열이 utf8mb4_unicode_ci
이면 행을 반환 하지만 배열이로 설정되어 있으면 행을 반환 하지 않습니다utf8mb4_general_ci
.
utf8mb4_unicode_ci 대신에 utf8mb4_general_ci를 사용하는 경우이 게시물에 따르면, MySQL은 5.7에 상당히 큰 성능 이점이있다 : https://www.percona.com/blog/2019/02/27/charset-and-collation-settings-impact -on-mysql-performance /