Giữa utf8_general_ci
và utf8_unicode_ci
, có sự khác biệt nào về hiệu suất?
utf8[mb4]_unicode_ci
, bạn có thể thích utf8[mb4]_unicode_520_ci
nhiều hơn nữa.
utf8mb4_0900_ai_ci
.
Giữa utf8_general_ci
và utf8_unicode_ci
, có sự khác biệt nào về hiệu suất?
utf8[mb4]_unicode_ci
, bạn có thể thích utf8[mb4]_unicode_520_ci
nhiều hơn nữa.
utf8mb4_0900_ai_ci
.
Câu trả lời:
Cả hai bộ sưu tập này đều dành cho mã hóa ký tự UTF-8. Sự khác biệt là cách văn bản được sắp xếp và so sánh.
Lưu ý: Trong MySQL bạn phải sử dụng utf8mb4
chứ không phải utf8
. Một cách khó hiểu, utf8
là một triển khai UTF-8 còn thiếu sót từ các phiên bản MySQL ban đầu chỉ còn để tương thích ngược. Phiên bản cố định đã được đặt tên utf8mb4
.
Lưu ý: Các phiên bản mới hơn của MySQL đã cập nhật các quy tắc sắp xếp Unicode, có sẵn dưới các tên như utf8mb4_0900_ai_ci
các quy tắc tương đương dựa trên Unicode 9.0 - và không có _general
biến thể tương đương . Những người đọc nó bây giờ có lẽ nên sử dụng một trong những bộ sưu tập mới hơn thay vì _unicode
hoặc _general
. Phần lớn những gì được viết dưới đây không còn được quan tâm nữa nếu bạn có thể sử dụng một trong những bộ sưu tập mới hơn để thay thế.
Sự khác biệt chính
utf8mb4_unicode_ci
được dựa trên các quy tắc Unicode chính thức để sắp xếp và so sánh phổ quát, sắp xếp chính xác trong một loạt các ngôn ngữ.
utf8mb4_general_ci
là một bộ quy tắc sắp xếp đơn giản hóa nhằm mục đích thực hiện tốt nhất có thể trong khi thực hiện nhiều thao tác rút gọn được thiết kế để cải thiện tốc độ. Nó không tuân theo các quy tắc Unicode và sẽ dẫn đến việc sắp xếp hoặc so sánh không mong muốn trong một số tình huống, chẳng hạn như khi sử dụng các ngôn ngữ hoặc ký tự cụ thể.
Trên các máy chủ hiện đại, hiệu suất tăng này sẽ là tất cả nhưng không đáng kể. Nó đã được nghĩ ra trong một thời gian khi các máy chủ có một phần rất nhỏ hiệu năng CPU của các máy tính ngày nay.
Lợi ích của utf8mb4_unicode_ci
hơnutf8mb4_general_ci
utf8mb4_unicode_ci
, sử dụng các quy tắc Unicode để sắp xếp và so sánh, sử dụng một thuật toán khá phức tạp để sắp xếp chính xác trong một loạt các ngôn ngữ và khi sử dụng một loạt các ký tự đặc biệt. Các quy tắc này cần phải tính đến các quy ước cụ thể về ngôn ngữ; không phải ai cũng sắp xếp các nhân vật của mình theo cái mà chúng ta gọi là "thứ tự chữ cái".
Theo như ngôn ngữ Latin (tức là "Châu Âu"), không có nhiều khác biệt giữa sắp xếp Unicode và utf8mb4_general_ci
sắp xếp đơn giản hóa trong MySQL, nhưng vẫn có một vài khác biệt:
Ví dụ: đối chiếu Unicode sắp xếp "ß" như "ss" và "" như "OE" như mọi người sử dụng các ký tự đó thường muốn, trong khi utf8mb4_general_ci
sắp xếp chúng thành các ký tự đơn (có lẽ giống như "s" và "e") .
Một số ký tự Unicode được định nghĩa là không thể biết được, điều đó có nghĩa là chúng không nên được tính theo thứ tự sắp xếp và thay vào đó nên chuyển sang ký tự tiếp theo. utf8mb4_unicode_ci
xử lý những điều này đúng.
Trong các ngôn ngữ phi Latinh, như ngôn ngữ châu Á hoặc ngôn ngữ có bảng chữ cái khác nhau, có thể có nhiều sự khác biệt hơn giữa sắp xếp Unicode và utf8mb4_general_ci
sắp xếp đơn giản hóa . Sự phù hợp của utf8mb4_general_ci
ý chí phụ thuộc rất nhiều vào ngôn ngữ được sử dụng. Đối với một số ngôn ngữ, nó sẽ khá bất cập.
Bạn nên dùng gì?
Gần như chắc chắn không có lý do để sử dụng utf8mb4_general_ci
nữa, vì chúng ta đã bỏ lại điểm mà tốc độ CPU đủ thấp để sự khác biệt hiệu năng sẽ là quan trọng. Cơ sở dữ liệu của bạn gần như chắc chắn sẽ bị giới hạn bởi các nút thắt khác hơn thế này.
Trước đây, một số người khuyên nên sử dụng utf8mb4_general_ci
trừ khi việc sắp xếp chính xác sẽ đủ quan trọng để biện minh cho chi phí hiệu suất. Ngày nay, chi phí hiệu năng đó đã biến mất và các nhà phát triển đang đối xử với quốc tế hóa nghiêm túc hơn.
Có một lập luận được đưa ra là nếu tốc độ quan trọng với bạn hơn độ chính xác, thì bạn cũng có thể không thực hiện bất kỳ sự sắp xếp nào cả. Thật là tầm thường để làm cho thuật toán nhanh hơn nếu bạn không cần nó chính xác. Vì vậy, utf8mb4_general_ci
là một sự thỏa hiệp có lẽ không cần thiết vì lý do tốc độ và có lẽ cũng không phù hợp với lý do chính xác.
Một điều khác tôi sẽ nói thêm là ngay cả khi bạn biết ứng dụng của mình chỉ hỗ trợ ngôn ngữ tiếng Anh, thì vẫn có thể cần xử lý tên của mọi người, thường có thể chứa các ký tự được sử dụng trong các ngôn ngữ khác, trong đó việc sắp xếp chính xác cũng quan trọng. . Sử dụng các quy tắc Unicode cho mọi thứ giúp bạn yên tâm hơn rằng những người Unicode rất thông minh đã làm việc rất chăm chỉ để sắp xếp công việc đúng cách.
Các bộ phận có nghĩa là gì
Thứ nhất, ci
là để phân loại và so sánh không phân biệt chữ hoa chữ thường . Điều này có nghĩa là nó phù hợp với dữ liệu văn bản và trường hợp không quan trọng. Các loại đối chiếu khác là cs
(phân biệt chữ hoa chữ thường) cho dữ liệu văn bản trong trường hợp là quan trọng và bin
đối với trường hợp mã hóa cần khớp, bit cho bit, phù hợp với các trường thực sự được mã hóa dữ liệu nhị phân (ví dụ: Cơ sở64). Sắp xếp phân biệt chữ hoa chữ thường dẫn đến một số kết quả kỳ lạ và so sánh phân biệt chữ hoa chữ thường có thể dẫn đến các giá trị trùng lặp chỉ khác nhau trong trường hợp chữ cái, do đó, các đối chiếu phân biệt chữ hoa chữ thường không phù hợp với dữ liệu văn bản - nếu trường hợp đó có ý nghĩa quan trọng đối với bạn và như vậy có lẽ cũng rất quan trọng, và đối chiếu nhị phân có thể phù hợp hơn.
Tiếp theo, unicode
hoặc general
đề cập đến các quy tắc sắp xếp và so sánh cụ thể - cụ thể, cách văn bản được chuẩn hóa hoặc so sánh. Có nhiều bộ quy tắc khác nhau cho mã hóa ký tự utf8mb4, unicode
và general
là hai bộ cố gắng hoạt động tốt trong tất cả các ngôn ngữ có thể thay vì một ngôn ngữ cụ thể. Sự khác biệt giữa hai bộ quy tắc này là chủ đề của câu trả lời này. Lưu ý rằng unicode
sử dụng các quy tắc từ Unicode 4.0. Các phiên bản gần đây của MySQL thêm các unicode_520
quy tắc sử dụng quy tắc từ Unicode 5.2 và 0900
(bỏ phần "unicode_") bằng cách sử dụng quy tắc từ Unicode 9.0.
Và cuối cùng, utf8mb4
tất nhiên là mã hóa ký tự được sử dụng trong nội bộ. Trong câu trả lời này, tôi chỉ nói về mã hóa dựa trên Unicode.
utf8_general_ci
: nó chỉ đơn giản không làm việc. Đó là một sự trở lại với những ngày xưa tồi tệ của sự khập khiễng của ASCII từ năm mươi năm trước. Kết hợp không phân biệt chữ hoa chữ thường có thể được thực hiện mà không có bản đồ chữ cái từ UCD. Ví dụ, trong đó có ba sigmas khác nhau trong đó; hoặc cách viết thường của dòng chữ TSCHüẞ Điên là một chữ viết hoa, nhưng chữ hoa của chữ viết hoa là chữ TSCHÜSS. Bạn có thể đúng, hoặc bạn có thể nhanh chóng. Do đó, bạn phải sử dụng utf8_unicode_ci
, bởi vì nếu bạn không quan tâm đến tính chính xác, thì việc làm cho nó nhanh chóng vô cùng.
"か" == "が"
hoặc "ǽ" == "æ"
. Để sắp xếp điều này có ý nghĩa nhưng có thể gây ngạc nhiên khi lựa chọn thông qua các đẳng thức hoặc xử lý các chỉ số duy nhất - bug.mysql.com/orms.php?id=16526
utf8mb4
là lựa chọn chính xác duy nhất . Với utf8
bạn bị mắc kẹt trong một số biến thể UTF8 chỉ có 3 byte của MySQL mà chỉ MySQL (và MariaDB) biết phải làm gì với. Phần còn lại của thế giới đang sử dụng UTF8, có thể chứa tối đa 4 byte cho mỗi ký tự . Các nhà phát triển MySQL đã đặt tên sai cho mã hóa homebrew của họ utf8
và để không phá vỡ tính tương thích ngược, giờ đây họ phải tham khảo UTF8 thực sự như utf8mb4
.
Tôi muốn biết sự khác biệt hiệu suất giữa việc sử dụng utf8_general_ci
và utf8_unicode_ci
, nhưng tôi không tìm thấy bất kỳ điểm chuẩn nào được liệt kê trên internet, vì vậy tôi đã quyết định tự tạo điểm chuẩn.
Tôi đã tạo một bảng rất đơn giản với 500.000 hàng:
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
Sau đó, tôi điền nó với dữ liệu ngẫu nhiên bằng cách chạy thủ tục được lưu trữ này:
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
Sau đó, tôi đã tạo các thủ tục được lưu trữ sau đây để điểm chuẩn đơn giản SELECT
, SELECT
với LIKE
và sắp xếp ( SELECT
với 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;
Trong các thủ tục lưu trữ trên utf8_general_ci
đối chiếu được sử dụng, nhưng tất nhiên trong các thử nghiệm tôi đã sử dụng cả utf8_general_ci
và utf8_unicode_ci
.
Tôi đã gọi mỗi thủ tục được lưu trữ 5 lần cho mỗi đối chiếu (5 lần cho utf8_general_ci
và 5 lần cho utf8_unicode_ci
) và sau đó tính các giá trị trung bình.
Kết quả của tôi là:
benchmark_simple_select()
utf8_general_ci
: 9,957 ms utf8_unicode_ci
: 10.271 ms Trong tiêu chuẩn này sử dụng utf8_unicode_ci
là chậm hơn utf8_general_ci
3,2%.
benchmark_select_like()
utf8_general_ci
: 11,441 ms utf8_unicode_ci
: 12.811 ms Trong tiêu chuẩn này sử dụng utf8_unicode_ci
là chậm hơn utf8_general_ci
12%.
benchmark_order_by()
utf8_general_ci
: 11.944 ms utf8_unicode_ci
: 12.887 ms Trong điểm chuẩn này, sử dụng utf8_unicode_ci
chậm hơn utf8_general_ci
7,9%.
utf8_general_ci
là quá tối thiểu để có giá trị sử dụng.
CONV(FLOOR(RAND() * 99999999999999), 20, 36)
chỉ tạo ASCII và không có ký tự Unicode nào được xử lý bằng thuật toán của các đối chiếu. 2) Description = 'test' COLLATE ...
và Description LIKE 'test%' COLLATE ...
chỉ xử lý một chuỗi ("kiểm tra") trong thời gian chạy, phải không? 3) Trong các ứng dụng thực, các cột được sử dụng theo thứ tự có thể sẽ được lập chỉ mục và tốc độ lập chỉ mục trên các đối chiếu khác nhau với văn bản không phải ASCII thực có thể khác nhau.
Bài đăng này mô tả nó rất độc đáo.
Tóm lại: utf8_unicode_ci sử dụng Thuật toán đối chiếu Unicode như được định nghĩa trong các tiêu chuẩn Unicode, trong khi utf8_general_ci là một thứ tự sắp xếp đơn giản hơn dẫn đến kết quả sắp xếp "kém chính xác" hơn.
utf8_unicode_ci
và giả vờ cái khác không tồn tại.
utf8_general_ci
có thể là dành cho bạn
Xem hướng dẫn sử dụng mysql, phần Bộ ký tự Unicode :
Đối với bất kỳ bộ ký tự Unicode nào, các thao tác được thực hiện bằng cách sử dụng đối chiếu _general_ci sẽ nhanh hơn các thao tác đối với đối chiếu _unicode_ci. Ví dụ, so sánh cho đối chiếu utf8_general_ci nhanh hơn, nhưng ít chính xác hơn so với so sánh cho utf8_unicode_ci. Lý do cho điều này là utf8_unicode_ci hỗ trợ ánh xạ như mở rộng; nghĩa là, khi một nhân vật so sánh bằng với sự kết hợp của các nhân vật khác. Ví dụ, trong tiếng Đức và một số ngôn ngữ khác, ßvà bằng với ss ss. utf8_unicode_ci cũng hỗ trợ các cơn co thắt và các ký tự không thể biết được. utf8_general_ci là một đối chiếu kế thừa không hỗ trợ các bản mở rộng, các cơn co thắt hoặc các ký tự không thể biết được. Nó chỉ có thể thực hiện so sánh một-một giữa các nhân vật.
Vì vậy, để tóm tắt, utf_general_ci sử dụng một bộ so sánh nhỏ hơn và ít chính xác hơn (theo tiêu chuẩn) so với utf_unicode_ci sẽ thực hiện toàn bộ tiêu chuẩn. Bộ general_ci sẽ nhanh hơn vì có ít tính toán hơn.
utf8_unicode_ci
và giả vờ phiên bản lỗi bị lỗi không tồn tại.
0
và 1
, không phải là một bool. :) EG chọn các điểm địa lý trong hộp giới hạn là một xấp xỉ 'điểm gần đó' không tốt bằng tính toán khoảng cách giữa điểm và điểm tham chiếu và lọc theo đó. Nhưng cả hai đều là một xấp xỉ và trên thực tế, tính chính xác hoàn toàn hầu như không thể đạt được. Xem nghịch lý đường bờ biển và IEEE 754
1/3
Nói ngắn gọn:
Nếu bạn cần sắp xếp thứ tự tốt hơn - sử dụng utf8_unicode_ci
(đây là phương pháp ưa thích),
nhưng nếu bạn hoàn toàn quan tâm đến hiệu suất - hãy sử dụng utf8_general_ci
, nhưng biết rằng nó hơi lỗi thời.
Sự khác biệt về hiệu suất là rất nhẹ.
Như chúng ta có thể đọc ở đây ( Peter Gulutzan ) có sự khác biệt trong việc sắp xếp / so sánh chữ đánh bóng "" (L với đột quỵ - html esc Ł
:) (chữ thường: "ł" - html esc ł
:) - chúng ta có giả định sau:
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
Trong thư ngôn ngữ đánh bóng Ł
là sau thư L
và trước M
. Không ai trong số mã hóa này tốt hơn hay xấu hơn - nó phụ thuộc vào nhu cầu của bạn.
Có hai sự khác biệt lớn về cách sắp xếp và khớp ký tự:
Phân loại :
utf8mb4_general_ci
xóa tất cả các dấu và sắp xếp từng điểm một có thể tạo ra kết quả sắp xếp không chính xác.utf8mb4_unicode_ci
sắp xếp chính xác.Phù hợp với nhân vật
Họ phù hợp với các nhân vật khác nhau.
Ví dụ, trong utf8mb4_unicode_ci
bạn có i != ı
, nhưng trong utf8mb4_general_ci
nó giữ ı=i
.
Ví dụ, hãy tưởng tượng bạn có một hàng với name="Yılmaz"
. Sau đó
select id from users where name='Yilmaz';
sẽ trả về hàng nếu sắp xếp thứ tự utf8mb4_general_ci
, nhưng nếu nó được sắp xếp chung utf8mb4_unicode_ci
thì nó sẽ không trả về hàng!
Mặt khác, chúng ta có điều đó a=ª
và ß=ss
trong utf8mb4_unicode_ci
đó không phải là trường hợp utf8mb4_general_ci
. Vì vậy, hãy tưởng tượng bạn có một hàng với name="ªßi"
, sau đó
select id from users where name='assi';
sẽ trả về hàng nếu collocation là utf8mb4_unicode_ci
, nhưng sẽ không trả về một hàng nếu collocation được đặt thành utf8mb4_general_ci
.
Một danh sách đầy đủ các trận đấu cho mỗi sắp xếp thứ tự có thể được tìm thấy ở đây .
Theo bài đăng này, có một lợi ích hiệu suất lớn đáng kể trên MySQL 5.7 khi sử dụng utf8mb4_general_ci thay cho utf8mb4_unicode_ci: https://www.percona.com/blog/2019/02/27/charset-and-collation-sinstall-impact -on-mysql-hiệu suất /