MySQL与PHP的最佳排序规则是什么?

MySQL与PHP的最佳排序规则是什么?,php,mysql,encoding,collation,Php,Mysql,Encoding,Collation,我想知道,对于一个你不能100%确定要输入什么的普通网站,MySQL中是否有一个“最佳”排序选择?我知道所有的编码都应该是相同的,比如MySQL、Apache、HTML和PHP中的任何东西 在过去,我将PHP设置为以“UTF-8”输出,但在MySQL中,这种排序规则与哪个排序规则匹配?我认为它是UTF-8之一,但我以前使用过utf8\u unicode\u ci,utf8\u general\u ci,以及utf8\u bin。对于UTF-8文本信息,您应该使用utf8\u general\u

我想知道,对于一个你不能100%确定要输入什么的普通网站,MySQL中是否有一个“最佳”排序选择?我知道所有的编码都应该是相同的,比如MySQL、Apache、HTML和PHP中的任何东西


在过去,我将PHP设置为以“UTF-8”输出,但在MySQL中,这种排序规则与哪个排序规则匹配?我认为它是UTF-8之一,但我以前使用过
utf8\u unicode\u ci
utf8\u general\u ci
,以及
utf8\u bin

对于UTF-8文本信息,您应该使用
utf8\u general\u ci
,因为

  • utf8\u bin
    :按 中每个字符的二进制值 弦

  • utf8\u常规\u ci
    :比较字符串 使用通用语言规则和 使用不区分大小写的比较


a、 k.a.这将使搜索和索引数据更快/更有效/更有用。

主要区别在于排序精度(在比较语言中的字符时)和性能。唯一特殊的是utf8_-bin,用于比较二进制格式的字符


utf8\u general\u ci
略快于
utf8\u unicode\u ci
,但精确度较低(用于排序)。特定语言utf8编码(如
utf8\u swedish\u ci
)包含额外的语言规则,使它们能够最准确地对这些语言进行排序。大多数情况下,我使用的是
utf8\u unicode\u ci
(我更喜欢精确性而不是小的性能改进),除非我有很好的理由选择特定的语言


您可以在MySQL手册上阅读有关特定unicode字符集的更多信息-

实际上,您可能希望使用
utf8\u unicode\u ci
utf8\u general\u ci

  • utf8\u general\u ci
    通过去除所有重音并像ASCII一样排序来进行排序
  • utf8\u unicode\u ci
    使用unicode排序顺序,因此它可以在更多语言中正确排序

但是,如果您仅使用它来存储英文文本,则它们应该没有区别。

排序规则会影响数据的排序方式以及字符串之间的比较方式。这意味着您应该使用大多数用户期望的排序规则

示例来自:

utf8\u常规\u ci
也令人满意 德语和法语,除了 ß等于s,而不是 “ss”。如果这对您的客户来说是可以接受的 应用程序,那么您应该使用
utf8\u general\u ci
,因为它速度更快。 否则,请使用
utf8\u unicode\u ci
它更准确


所以-这取决于您预期的用户群以及您需要正确排序的程度。对于英语用户群,
utf8\u general\u ci
应该足够了,对于其他语言,如瑞典语,已经创建了特殊的排序规则。

请非常、非常注意使用
utf8\u general\u ci
时可能出现的问题

如果使用
utf8\u general\u ci
排序规则,MySQL将不会区分select语句中的某些字符。这可能会导致非常严重的bug,特别是在涉及用户名的情况下。根据使用数据库表的实现,此问题可能允许恶意用户创建与管理员帐户匹配的用户名

这个问题至少在早期的5.x版本中会暴露出来——我不确定这种行为以后是否会改变

我不是DBA,但为了避免这个问题,我总是使用
utf8-bin
,而不是不区分大小写的

下面的脚本通过示例描述了该问题

——首先,创建一个沙盒来播放
创建数据库“沙盒”;
使用“沙盒”;
--接下来,确保您的客户端连接是相同的
--我们下一步要测试的字符/校对类型:
字符集utf8对比utf8\u常规\u ci
--现在,创建表并用值填充它
创建表`test`(`key`VARCHAR(16),`value`VARCHAR(16))
字符集utf8校对utf8\u常规\u ci;
插入'test'值('Key ONE','value'),('Key TWO','valúe');
--(核实)
从“测试”中选择*;
--现在,暴露问题/bug:
从测试中选择*,其中'value`='value';
--
--请注意,我们在这里得到两个键!MySQLs UTF8整理的
--不区分大小写(以_ci结尾)不区分
--两种价值观!
--
--collate'utf8_-bin'没有这个问题,我将在下面展示:
--
--首先,重置客户端连接字符集/排序类型
字符集utf8校对utf8\u bin
--接下来,转换我们先前插入到表中的值
ALTER TABLE`test`转换为字符集utf8 COLLATE utf8\u bin;
--现在,重新检查错误
从测试中选择*,其中'value`='value';
--
--请注意,正如您所期望的,我们现在只得到一个键。
--
--此问题似乎是utf8特有的。下一步,我将尝试
--对“latin1”字符集执行相同的操作:
--
--首先,重置客户端连接字符集/排序类型
字符集拉丁1校对拉丁1\u通用\u ci
--接下来,转换我们先前插入的值
--在桌子上
ALTER TABLE`test`转换为字符集latin1 COLLATE latin1\u general\u ci;
--现在,重新检查错误
从测试中选择*,其中'value`='value';
--
--同样,只返回一个键(预期)。这表明
--utf8/utf8\u通用\u ci的问题不存在
--拉丁语/拉丁语通用
--
--为了完成这个示例,我将使用二进制collate进行检查
--还有拉丁语1:
--首先,重置客户端连接字符集/排序类型
字符集拉丁1校对拉丁1_bin
--接下来,转换我们先前插入到表中的值
ALTER TABLE`test`转换为字符集latin1 COLLATE latin1_bin;
--现在,重新检查错误
从测试中选择*,其中'value`='value';
--
--同样,只返回一个键(预期)。
--
--最后,我将以完全相同的方式重新介绍这个问题
SHOW VARIABLES;

innodb_large_prefix = OFF
innodb_file_format = Antelope
[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
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;
INDEX contact_idx (contact(128)),
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', 'I found these collation charts helpful. http://collation-charts.org/mysql60/. I'm no sure which is the used utf8_general_ci though.

For example here is the chart for utf8_swedish_ci. It shows which characters it interprets as the same. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html

In your database upload file, add the followin line before any line:

SET NAMES utf8;