Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 澄清非二进制排序中重音字符相等的潜在问题_Mysql_Collation_Non Ascii Characters - Fatal编程技术网

Mysql 澄清非二进制排序中重音字符相等的潜在问题

Mysql 澄清非二进制排序中重音字符相等的潜在问题,mysql,collation,non-ascii-characters,Mysql,Collation,Non Ascii Characters,对于具有国际支持的网站,我在大多数表和列中使用utf8mb4字符集和utf8mb4_unicode_ci排序规则。性能不是最重要的,在多种语言中准确排序很重要 我了解utf8mb4_general_ci和utf8mb4_unicode_ci排序规则通常如何与重音字符进行比较,即: SELECT column FROM table WHERE column='abad'; 将同时返回“abad”和“abád” 在研究MySQL中的utf8支持时,我遇到了一个非二进制utf8排序规则的假定问题。位

对于具有国际支持的网站,我在大多数表和列中使用utf8mb4字符集和utf8mb4_unicode_ci排序规则。性能不是最重要的,在多种语言中准确排序很重要

我了解utf8mb4_general_ci和utf8mb4_unicode_ci排序规则通常如何与重音字符进行比较,即:

SELECT column FROM table WHERE column='abad';
将同时返回“abad”和“abád”

在研究MySQL中的utf8支持时,我遇到了一个非二进制utf8排序规则的假定问题。位于的页面描述了某些更新中未保存更改的问题。他说,“当更新记录时,MySQL(或至少InnoDB)会在更新记录之前检查是否相等。由于排序规则认为只有重音的更改是相等的,MySQL跳过写操作(这节省了I/O开销),并返回成功,因为它认为它优化了写操作,而不是失败。”

我将其解释为:如果您试图更新一条记录,只对字段的重音进行更改,它将无法正确更新(因为MySQL认为它已经匹配)。但我无法复制这一点。我创建了一个简单的测试用例:

CREATE DATABASE test_utf8 
    CHARACTER SET utf8mb4 
    COLLATE utf8mb4_unicode_ci;

USE test_utf8;

CREATE TABLE test (
    id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, 
    text VARCHAR(300) NOT NULL, 
    PRIMARY KEY (id)
) ENGINE = INNODB;

INSERT INTO test (text) VALUES ('abád');

UPDATE test SET text='abad' WHERE id=1;
但是,这会正确更新该值(尽管只有一个字符的重音发生了更改)。这是否只是MySQL旧版本中的一个问题?或者这个问题是在稍微不同的情况下出现的


如果您有时间阅读我关于这个主题的一些概念的笔记,看看我是否有任何误解,我也将不胜感激。如果它是无错误的,也许它对某些人来说是有用的信息

MySQL的utf8字符集不提供真正的utf8支持,因为字符只有1-3个字节。要获得真正的utf8支持,您可能需要使用utf8mb4

一般来说,utf8mb4_unicode_ci使用适合于语言的排序将更加准确,但与使用utf8mb4_general_ci相比,性能受到了轻微的影响

如果某些列不需要排序,并且将使用比较/相等检查,则应使用utf8mb4_bin,因为它会稍微快一点

在utf8mb4_general_ci和utf8mb4_unicode_ci排序规则中,重音字符被视为相等。因此,对于必须具有唯一值(例如主键)的列,这是一个错误的排序规则选择。在这种情况下,应使用utf8mb4_-bin。如果一个字段需要注意重音以获得唯一性,但在某些时候还需要进行语言排序,则可以将其存储为utf8mb4_bin,并且在排序时可以在查询中使用collate子句。例:

SELECT column FROM table ORDER BY column COLLATE utf8mb4_unicode_ci;
这将导致排序被语言排序,尽管其内部存储在二进制排序规则中。这将影响性能,因为字段的排序规则决定了它的索引方式。查询的性能差异类似于对未索引列和索引列进行排序时的性能差异

默认情况下,在utf8mb4_unicode_ci或utf8mb4_general_ci排序规则下进行的搜索不会识别重音,因此搜索“abad”将返回“abad”和“abád”。因此,如果希望进行重音识别搜索,则必须将列的排序规则设置为utf8mb4_binary(如果所有搜索都对重音敏感),或者在查询中使用collate子句(如果希望大多数搜索不带重音)。由于utf8mb4_-bin排序规则区分大小写,如果希望进行不区分大小写但区分重音的搜索,还需要修改查询。例如(假设您的搜索词已在服务器端脚本语言中变为小写):


另外,在MySQL文档中(包括其他文档):在比较不同列的值时,尽可能使用相同的字符集和排序规则声明这些列,以避免在运行查询时进行字符串转换

我不是专家,但我试过你用一些额外的东西做的

我在MySQL 5.6.17上运行了您的设置和以下内容:

SELECT COUNT(*) FROM test WHERE `text`='abad';
SELECT COUNT(*) FROM test WHERE `text`='abád';
UPDATE test SET text='abád' WHERE id=1;
正如我们所期望的,选择返回1行,更新(像您的更新一样)修改1行,与博客建议相反

我认为这可能是一个较低级别的优化,但当我尝试在命令行客户机(而不是工作台)中再次运行它时,我注意到了一些有趣的事情:

所以我运行这个来看看发生了什么:

mysql> SELECT collation('abád');
+-------------------+
| collation('abád')  |
+-------------------+
| utf8_general_ci   |
+-------------------+
1 row in set (0.00 sec)
由于会话集的原因,必须进行一些强制操作…因此我尝试显式匹配:

UPDATE test SET text='abad' COLLATE utf8_unicode_ci WHERE id=1;
UPDATE test SET text='abád' COLLATE utf8_unicode_ci WHERE id=1;
但我还是得到了同样的结果(两次更新)

现在,我只剩下我的猜测,InnoDB的优化是在一个比根据文本标准选择更低的级别上完成的

mysql> SELECT collation('abád');
+-------------------+
| collation('abád')  |
+-------------------+
| utf8_general_ci   |
+-------------------+
1 row in set (0.00 sec)
UPDATE test SET text='abad' COLLATE utf8_unicode_ci WHERE id=1;
UPDATE test SET text='abád' COLLATE utf8_unicode_ci WHERE id=1;