Đối chiếu tốt nhất để sử dụng cho MySQL với PHP là gì? [đóng cửa]


731

Tôi tự hỏi liệu có sự lựa chọn "tốt nhất" nào cho việc đối chiếu trong MySQL cho một trang web chung mà bạn không chắc chắn 100% về những gì sẽ được nhập không? Tôi hiểu rằng tất cả các mã hóa phải giống nhau, chẳng hạn như MySQL, Apache, HTML và bất cứ thứ gì trong PHP.

Trước đây tôi đã đặt PHP thành đầu ra trong "UTF-8", nhưng đối chiếu nào phù hợp với điều này trong MySQL? Tôi nghĩ nó là một trong những UTF-8 người, nhưng tôi đã sử dụng utf8_unicode_ci, utf8_general_ciutf8_bintrước đó.


35
Lưu ý bên lề: "utf8" của MySQL không phải là UTF-8 thích hợp (không hỗ trợ cho hơn 4 ký tự Unicode byte như 𝌆), tuy nhiên "utf8mb4" là. Với utf8, một trường sẽ bị cắt ngắn khi chèn bắt đầu bằng ký tự Unicode không được hỗ trợ đầu tiên. mathiasbynens.be/notes/mysql-utf8mb4
basic6

6
Tôi tự hỏi liệu chúng ta có cần 5 byte cho tất cả những biểu tượng cảm xúc đó không ... thở dài
Álvaro González

1
Câu hỏi liên quan: stackoverflow.com/questions/38228335/ '"Đối chiếu MySQL nào khớp chính xác với so sánh chuỗi của PHP?"
William Entriken

Để biết tổng quan về các tùy chọn lành mạnh: monolune.com/mysql-utf8-charsets-and-collations-explained
Flux

Câu trả lời:


618

Sự khác biệt chính là sắp xếp độ chính xác (khi so sánh các ký tự trong ngôn ngữ) và hiệu suất. Điều đặc biệt duy nhất là utf8_bin dùng để so sánh các ký tự ở định dạng nhị phân.

utf8_general_cicó phần nhanh hơn utf8_unicode_ci, nhưng kém chính xác hơn (để sắp xếp). Các utf8 mã hóa ngôn ngữ cụ thể (như utf8_swedish_ci) có chứa quy tắc ngôn ngữ bổ sung mà làm cho họ chính xác nhất để sắp xếp cho những ngôn ngữ. Hầu hết thời gian tôi sử dụng utf8_unicode_ci(tôi thích độ chính xác cho các cải tiến hiệu suất nhỏ), trừ khi tôi có lý do chính đáng để thích một ngôn ngữ cụ thể.

Bạn có thể đọc thêm về các bộ ký tự unicode cụ thể trong hướng dẫn sử dụng MySQL - http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html


4
cải thiện hiệu suất nhỏ? Bạn có chắc về điều này ? publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/ mẹo Việc đối chiếu bạn chọn có thể ảnh hưởng đáng kể đến hiệu suất của các truy vấn trong cơ sở dữ liệu.
Adam Ramadhan

62
Cái này dành cho DB2 chứ không phải MySQL. Ngoài ra, không có con số cụ thể hoặc điểm chuẩn, vì vậy bạn chỉ dựa trên ý kiến ​​của người viết.
Eran Galperin

3
Lưu ý rằng nếu bạn muốn sử dụng các hàm, có một lỗi trong MySQL (phiên bản được phân phối hiện tại nhất) trong đó các hàm luôn trả về chuỗi bằng utf8_general_ci, gây ra sự cố nếu bạn đang sử dụng đối chiếu khác cho chuỗi của mình - xem bug.mysql.com/ bug.php? id = 24690
El Yobo

1
Từ kinh nghiệm của tôi với các địa phương khác nhau, tôi luôn sử dụngutf8_unicode_*
Shiplu Mokaddim

11
Cập nhật: Đối với các phiên bản mới hơn, khuyến nghị utf8mb4utf8mb4_unicode_520_ci. Những thứ này cung cấp cho bạn phần còn lại của tiếng Trung, cộng với sự đối chiếu được cải thiện.
Rick James

129

Trên thực tế, bạn có thể muốn sử dụng utf8_unicode_cihoặc utf8_general_ci.

  • utf8_general_ci sắp xếp bằng cách tước đi tất cả các dấu và sắp xếp như thể đó là ASCII
  • utf8_unicode_ci sử dụng thứ tự sắp xếp Unicode, vì vậy nó sắp xếp chính xác trong nhiều ngôn ngữ

Tuy nhiên, nếu bạn chỉ sử dụng điều này để lưu trữ văn bản tiếng Anh, những điều này không nên khác nhau.


1
Tôi thích lời giải thích của bạn! Tốt một. Nhưng tôi cần hiểu rõ hơn về chính xác lý do tại sao thứ tự unicode là cách tốt hơn để sắp xếp chính xác hơn là tước đi các dấu.
thiết kế weia

14
@Adam Nó thực sự phụ thuộc vào đối tượng mục tiêu của bạn. Sắp xếp là một vấn đề khó khăn để bản địa hóa chính xác. Ví dụ, trong tiếng Na Uy, các chữ cái Æ Ø là 3 chữ cái cuối cùng. Với utf8_general_ci, Ø và được chuyển đổi thành O và A, điều này đặt chúng ở vị trí hoàn toàn sai khi được sắp xếp (tôi không chắc cách xử lý, vì nó là một chữ ghép, không phải là ký tự có dấu). Thứ tự sắp xếp này khác nhau ở hầu hết mọi ngôn ngữ, ví dụ Na Uy và Thụy Điển có các thứ tự khác nhau (và các chữ cái hơi khác nhau được coi là bằng nhau): Æ Ø được sắp xếp Æ (các chữ cái thực tế là Å Ä Ö). Unicode sửa lỗi này.
Vegard Larsen

Vì vậy, điều tôi nói cơ bản là, có lẽ bạn nên sử dụng một loại sắp xếp theo ngôn ngữ cụ thể nếu bạn có thể, nhưng trong hầu hết các trường hợp không khả thi, vì vậy hãy tìm cách sắp xếp chung Unicode. Nó vẫn sẽ là lạ trong một số ngôn ngữ, nhưng chính xác hơn ASCII.
Vegard Larsen

3
@Manatax - với bất kỳ bộ sưu tập utf8_ nào, dữ liệu được lưu trữ dưới dạng utf8. Đối chiếu chỉ là về những gì các nhân vật được coi là bằng nhau và cách họ được sắp xếp.
Frymaster

2
@frymaster - không đúng sự thật, theo: mathiasbynens.be/notes/mysql-utf8mb4 "utf8 MySQL chỉ cho phép bạn lưu trữ 5,88% của tất cả các điểm mã Unicode càng tốt"
dữ liệu

120

Hãy rất, rất ý thức về vấn đề này có thể xảy ra khi sử dụng utf8_general_ci.

MySQL sẽ không phân biệt giữa một số ký tự trong các câu lệnh chọn, nếu utf8_general_ciđối chiếu được sử dụng. Điều này có thể dẫn đến các lỗi rất khó chịu - đặc biệt là, ví dụ, nơi có tên người dùng. Tùy thuộc vào việc triển khai sử dụng các bảng cơ sở dữ liệu, vấn đề này có thể cho phép người dùng độc hại tạo tên người dùng khớp với tài khoản quản trị viên.

Vấn đề này phơi bày ít nhất ở các phiên bản 5.x đầu tiên - Tôi không chắc hành vi này có thay đổi sau này không.

Tôi không phải là DBA, nhưng để tránh vấn đề này, tôi luôn đi theo utf8-binthay vì một trường hợp không nhạy cảm.

Kịch bản dưới đây mô tả vấn đề bằng ví dụ.

-- first, create a sandbox to play in
CREATE DATABASE `sandbox`;
use `sandbox`;

-- next, make sure that your client connection is of the same 
-- character/collate type as the one we're going to test next:
charset utf8 collate utf8_general_ci

-- now, create the table and fill it with values
CREATE TABLE `test` (`key` VARCHAR(16), `value` VARCHAR(16) )
    CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO `test` VALUES ('Key ONE', 'value'), ('Key TWO', 'valúe');

-- (verify)
SELECT * FROM `test`;

-- now, expose the problem/bug:
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get BOTH keys here! MySQLs UTF8 collates that are 
-- case insensitive (ending with _ci) do not distinguish between 
-- both values!
--
-- collate 'utf8_bin' doesn't have this problem, as I'll show next:
--

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get just one key now, as you'd expect.
--
-- This problem appears to be specific to utf8. Next, I'll try to 
-- do the same with the 'latin1' charset:
--

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_general_ci

-- next, convert the values that we've previously inserted
-- in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_general_ci;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected). This shows 
-- that the problem with utf8/utf8_generic_ci isn't present 
-- in latin1/latin1_general_ci
--
-- To complete the example, I'll check with the binary collate
-- of latin1 as well:

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected).
--
-- Finally, I'll re-introduce the problem in the exact same 
-- way (for any sceptics out there):

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_generic_ci

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

-- now, re-check for the problem/bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Two keys.
--

DROP DATABASE sandbox;

36
-1: Điều này chắc chắn được khắc phục bằng cách áp dụng một khóa duy nhất cho cột có liên quan. Bạn sẽ thấy hành vi tương tự nếu hai giá trị là 'value''valUe'. Toàn bộ quan điểm của một đối chiếu là nó cung cấp các quy tắc cho (trong số những thứ khác) khi hai chuỗi được coi là bằng nhau.
Hammerite

13
Đó chính xác là vấn đề mà tôi đang cố gắng minh họa - sự đối chiếu làm cho hai thứ bằng nhau trong khi thực tế chúng không có ý định bằng nhau (và do đó, một ràng buộc duy nhất hoàn toàn trái ngược với những gì bạn muốn đạt được)
Guus

18
Nhưng bạn mô tả nó như là một "vấn đề" và dẫn đến "lỗi" khi hành vi đó chính xác là những gì đối chiếu dự định đạt được. Mô tả của bạn là chính xác, nhưng chỉ là một lỗi của DBA để chọn một đối chiếu không phù hợp.
Hammerite

32
Vấn đề là, khi bạn nhập hai tên người dùng được coi là bằng nhau đối chiếu, sẽ không được phép nếu bạn đặt tên người dùng coloumn là duy nhất, điều mà tất nhiên bạn nên làm!
Học sinh của Hogwarts

12
Tôi ủng hộ cả câu trả lời này và nhận xét của @ Hammerite, bởi vì cả hai kết hợp lại giúp tôi đạt được sự hiểu biết về đối chiếu.
Nacht - Tái lập Monica

86

Tốt nhất là sử dụng bộ ký tự utf8mb4với đối chiếu utf8mb4_unicode_ci.

Bộ ký tự utf8, chỉ hỗ trợ một lượng nhỏ điểm mã UTF-8, khoảng 6% ký tự có thể. utf8chỉ hỗ trợ Mặt phẳng đa ngôn ngữ cơ bản (BMP). Có 16 máy bay khác. Mỗi mặt phẳng chứa 65.536 ký tự. utf8mb4hỗ trợ tất cả 17 máy bay.

MySQL sẽ cắt bớt 4 ký tự UTF-8 byte dẫn đến dữ liệu bị hỏng.

Bộ utf8mb4ký tự được giới thiệu trong MySQL 5.5.3 vào ngày 2010-03-24.

Một số thay đổi bắt buộc để sử dụng bộ ký tự mới không phải là nhỏ:

  • Thay đổi có thể cần phải được thực hiện trong bộ điều hợp cơ sở dữ liệu ứng dụng của bạn.
  • Các thay đổi sẽ cần được thực hiện đối với my.cnf, bao gồm thiết lập bộ ký tự, đối chiếu và chuyển đổi innodb_file_format sang Barracuda
  • Các câu lệnh SQL CREATE có thể cần bao gồm: ROW_FORMAT=DYNAMIC
    • NĂNG ĐỘNG là cần thiết cho các chỉ mục trên VARCHAR (192) và lớn hơn.

LƯU Ý: Chuyển sang Barracudatừ Antelope, có thể yêu cầu khởi động lại dịch vụ MySQL nhiều lần. innodb_file_format_maxkhông thay đổi cho đến khi dịch vụ MySQL được khởi động lại thành : innodb_file_format = barracuda.

MySQL sử dụng Antelopeđịnh dạng tệp InnoDB cũ . Barracudahỗ trợ các định dạng hàng động mà bạn sẽ cần nếu bạn không muốn gặp các lỗi SQL để tạo chỉ mục và khóa sau khi bạn chuyển sang bộ ký tự:utf8mb4

  • # 1709 - Kích thước cột chỉ mục quá lớn. Kích thước cột tối đa là 767 byte.
  • # 1071 - Khóa được chỉ định quá dài; độ dài khóa tối đa là 767 byte

Kịch bản sau đây đã được thử nghiệm trên MySQL 5.6.17: Theo mặc định, MySQL được cấu hình như thế này:

SHOW VARIABLES;

innodb_large_prefix = OFF
innodb_file_format = Antelope

Dừng dịch vụ MySQL của bạn và thêm các tùy chọn vào my.cnf hiện tại của bạn:

[client]
default-character-set= utf8mb4

[mysqld]
explicit_defaults_for_timestamp = true
innodb_large_prefix = true
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = true

# Character collation
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci

Ví dụ câu lệnh SQL CREATE:

CREATE TABLE Contacts (
 id INT AUTO_INCREMENT NOT NULL,
 ownerId INT DEFAULT NULL,
 created timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 contact VARCHAR(640) NOT NULL,
 prefix VARCHAR(128) NOT NULL,
 first VARCHAR(128) NOT NULL,
 middle VARCHAR(128) NOT NULL,
 last VARCHAR(128) NOT NULL,
 suffix VARCHAR(128) NOT NULL,
 notes MEDIUMTEXT NOT NULL,
 INDEX IDX_CA367725E05EFD25 (ownerId),
 INDEX created (created),
 INDEX modified_idx (modified),
 INDEX contact_idx (contact),
 PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT=DYNAMIC;
  • Bạn có thể thấy lỗi # 1709 được tạo INDEX contact_idx (contact)nếu ROW_FORMAT=DYNAMICbị xóa khỏi câu lệnh CREATE.

LƯU Ý: Thay đổi chỉ mục để giới hạn ở 128 ký tự đầu tiên về contactviệc loại bỏ yêu cầu sử dụng Barracuda vớiROW_FORMAT=DYNAMIC

INDEX contact_idx (contact(128)),

Cũng lưu ý: khi nó nói kích thước của trường là VARCHAR(128), đó không phải là 128 byte. Bạn có thể sử dụng có 128, 4 ký tự byte hoặc ký tự 128, 1 byte.

Câu INSERTlệnh này phải chứa ký tự 'poo' 4 byte trong hàng 2:

INSERT INTO `Contacts` (`id`, `ownerId`, `created`, `modified`, `contact`, `prefix`, `first`, `middle`, `last`, `suffix`, `notes`) VALUES
(1, NULL, '0000-00-00 00:00:00', '2014-08-25 03:00:36', '1234567890', '12345678901234567890', '1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678', '', ''),
(2, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '', ''),
(3, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '123💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '', '');

Bạn có thể thấy lượng không gian được sử dụng bởi lastcột:

mysql> SELECT BIT_LENGTH(`last`), CHAR_LENGTH(`last`) FROM `Contacts`;
+--------------------+---------------------+
| BIT_LENGTH(`last`) | CHAR_LENGTH(`last`) |
+--------------------+---------------------+
|               1024 |                 128 | -- All characters are ASCII
|               4096 |                 128 | -- All characters are 4 bytes
|               4024 |                 128 | -- 3 characters are ASCII, 125 are 4 bytes
+--------------------+---------------------+

Trong bộ điều hợp cơ sở dữ liệu của bạn, bạn có thể muốn đặt bộ ký tự và đối chiếu cho kết nối của mình:

SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'

Trong PHP, điều này sẽ được đặt cho: \PDO::MYSQL_ATTR_INIT_COMMAND

Người giới thiệu:




6
utf8mb4_unicode_ci hoàn toàn nên là đối chiếu được đề xuất cho các dự án mới trong năm 2015.
Trevor Gehman 7/07/2015

7
Cập nhật ... utf8mb4_unicode_520_cilà tốt hơn. Trong tương lai, sẽ có utf8mb4_unicode_800_ci(hoặc một cái gì đó tương tự), khi MySQL bắt kịp với các tiêu chuẩn Unicode.
Rick James

46

Các bộ sưu tập ảnh hưởng đến cách sắp xếp dữ liệu và cách các chuỗi được so sánh với nhau. Điều đó có nghĩa là bạn nên sử dụng đối chiếu mà hầu hết người dùng của bạn mong đợi.

Ví dụ từ tài liệu cho bộ ký tự unicode :

utf8_general_cicũng thỏa đáng cho cả tiếng Đức và tiếng Pháp, ngoại trừ 'ß' bằng với 's' và không bằng 'ss'. Nếu điều này được chấp nhận cho ứng dụng của bạn, thì bạn nên sử dụng utf8_general_civì nó nhanh hơn. Nếu không, sử dụng utf8_unicode_civì nó chính xác hơn.

Vì vậy - nó phụ thuộc vào cơ sở người dùng dự kiến ​​của bạn và vào mức độ bạn cần sắp xếp chính xác . Đối với một cơ sở người dùng tiếng Anh, utf8_general_cinên đủ, đối với các ngôn ngữ khác, như tiếng Thụy Điển, các bộ sưu tập đặc biệt đã được tạo.


1
tôi đã sử dụng utf8_general_ci và mất vài giây trong khi sắp xếp và armscii_general_ci đã làm điều đó cực kỳ nhanh chóng. Tại sao điều này xảy ra? Một câu hỏi nữa, bạn nghĩ gì về việc đối chiếu được sử dụng bởi các trang mạng xã hội

22

Về cơ bản, nó phụ thuộc vào cách bạn nghĩ về một chuỗi.

Tôi luôn sử dụng utf8_bin vì sự cố được đánh dấu bởi Guus. Theo tôi, khi có liên quan đến cơ sở dữ liệu, một chuỗi vẫn chỉ là một chuỗi. Một chuỗi là một số ký tự UTF-8. Một ký tự có biểu diễn nhị phân, vậy tại sao nó cần biết ngôn ngữ bạn đang sử dụng? Thông thường, mọi người sẽ xây dựng cơ sở dữ liệu cho các hệ thống với phạm vi cho các trang web đa ngôn ngữ. Đây là toàn bộ quan điểm của việc sử dụng UTF-8 làm bộ ký tự. Tôi là một người theo chủ nghĩa thuần túy nhưng tôi nghĩ rằng rủi ro lỗi lớn hơn nhiều so với lợi thế nhỏ mà bạn có thể có được khi lập chỉ mục. Bất kỳ quy tắc liên quan đến ngôn ngữ nên được thực hiện ở mức cao hơn nhiều so với DBMS.

Trong sách của tôi, "giá trị" không bao giờ nên trong một triệu năm bằng "valúe".

Nếu tôi muốn lưu trữ một trường văn bản và thực hiện tìm kiếm không phân biệt chữ hoa chữ thường, tôi sẽ sử dụng các hàm chuỗi MYSQL với các hàm PHP như LOWER () và hàm strtolower của hàm php ().


9
Nếu so sánh nhị phân của chuỗi là so sánh mong muốn của bạn, thì tất nhiên bạn nên sử dụng đối chiếu nhị phân; nhưng để loại bỏ các đối chiếu thay thế là "rủi ro lỗi" hoặc chỉ đơn giản là để thuận tiện cho việc lập chỉ mục cho thấy rằng bạn không hiểu đầy đủ quan điểm của đối chiếu.
Hammerite

13

Đối với thông tin văn bản UTF-8, bạn nên sử dụng utf8_general_civì ...

  • utf8_bin: so sánh các chuỗi theo giá trị nhị phân của từng ký tự trong chuỗi

  • utf8_general_ci: so sánh các chuỗi sử dụng các quy tắc ngôn ngữ chung và sử dụng các so sánh không phân biệt chữ hoa chữ thường

aka nó sẽ làm cho việc tìm kiếm và lập chỉ mục dữ liệu nhanh hơn / hiệu quả hơn / hữu ích hơn.


12

Câu trả lời được chấp nhận khá dứt khoát đề nghị sử dụng utf8_unicode_ci và trong khi đối với các dự án mới tuyệt vời, tôi muốn liên hệ với trải nghiệm trái ngược gần đây của mình chỉ trong trường hợp nó giúp tiết kiệm thời gian cho bất cứ ai.

Vì utf8_general_ci là đối chiếu mặc định cho Unicode trong MySQL, nếu bạn muốn sử dụng utf8_unicode_ci thì cuối cùng bạn phải chỉ định nó ở nhiều nơi.

Ví dụ: tất cả các kết nối máy khách không chỉ có bộ ký tự mặc định (có ý nghĩa với tôi) mà còn có đối chiếu mặc định (nghĩa là đối chiếu sẽ luôn mặc định là utf8_general_ci cho unicode).

Có thể, nếu bạn sử dụng utf8_unicode_ci cho các trường của mình, các tập lệnh kết nối với cơ sở dữ liệu sẽ cần được cập nhật để đề cập đến đối chiếu mong muốn một cách rõ ràng - nếu không các truy vấn sử dụng chuỗi văn bản có thể thất bại khi kết nối của bạn đang sử dụng đối chiếu mặc định.

Kết quả cuối cùng là khi chuyển đổi một hệ thống hiện có ở bất kỳ kích thước nào sang Unicode / utf8, cuối cùng bạn có thể bị buộc phải sử dụng utf8_general_ci do cách MySQL xử lý mặc định.


8

Đối với trường hợp được đánh dấu bởi Guus, tôi thực sự khuyên bạn nên sử dụng utf8_unicode_cs (phân biệt chữ hoa chữ thường, khớp nghiêm ngặt, sắp xếp chính xác cho hầu hết các phần) thay vì utf8_bin (khớp nghiêm ngặt, đặt hàng không chính xác).

Nếu trường được dự định tìm kiếm, trái ngược với đối sánh cho người dùng, thì hãy sử dụng utf8_general_ci hoặc utf8_unicode_ci. Cả hai đều không phân biệt chữ hoa chữ thường, một người sẽ thua khớp ('ß' bằng với 's' và không bằng 'ss'). Ngoài ra còn có các phiên bản dành riêng cho ngôn ngữ, như utf8_german_ci trong đó kết quả khớp phù hợp hơn với ngôn ngữ được chỉ định.

[Chỉnh sửa - gần 6 năm sau]

Tôi không còn đề xuất bộ ký tự "utf8" trên MySQL và thay vào đó đề xuất bộ ký tự "utf8mb4". Chúng khớp gần như hoàn toàn, nhưng cho phép thêm một (rất nhiều) ký tự unicode.

Trên thực tế, MySQL nên cập nhật bộ ký tự "utf8" và các bộ sưu tập tương ứng để phù hợp với đặc điểm kỹ thuật "utf8", nhưng thay vào đó, một bộ ký tự riêng và các bộ sưu tập tương ứng để không ảnh hưởng đến chỉ định lưu trữ cho những người đã sử dụng bộ ký tự "utf8" chưa hoàn chỉnh của chúng .


5
FYI: utf8_unicode_cskhông tồn tại. Các utf8 trường hợp nhạy cảm duy nhất là utf8_bin. Vấn đề là utf8_binsắp xếp không chính xác. Xem: stackoverflow.com/questions/15218077/ Mạnh
Costa

1
Cảm ơn đã cập nhật!
Prometheus

5

Tôi tìm thấy những biểu đồ đối chiếu hữu ích. http://collation-charts.org/mysql60/ . Tôi không chắc chắn đó là utf8_general_ci được sử dụng mặc dù.

Ví dụ ở đây là biểu đồ cho utf8_swbur_ci. Nó cho thấy những ký tự mà nó diễn giải là giống nhau. http://collation-charts.org/mysql60/mysql604.utf8_swbur_ci.html


Một hương vị khác nhau của biểu đồ: mysql.rjweb.org/utf8_collations.html
Rick James

2

Trong tệp tải lên cơ sở dữ liệu của bạn, hãy thêm dòng theo dõi trước bất kỳ dòng nào:

SET NAMES utf8;

Và vấn đề của bạn nên được giải quyết.


2
Đọc một câu hỏi: Trước đây tôi đã đặt PHP thành đầu ra trong "UTF-8", nhưng đối chiếu nào phù hợp với điều này trong MySQL? Tôi nghĩ đó là một trong những UTF-8, nhưng tôi đã sử dụng utf8_unicode_ci, utf8_general_ci và utf8_bin trước đây.
Jitesh Sojitra

5
Câu trả lời này không liên quan gì đến câu hỏi. Ngoài ra, việc đưa ra một SET NAMEStruy vấn trực tiếp không cho khách hàng biết về mã hóa và có thể phá vỡ một số tính năng nhất định như các câu lệnh được chuẩn bị theo một cách rất tinh tế.
Álvaro González
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.