MySQL:整理查询 - 有任何副作用吗?

MySQL: Collate in query - any side effects?

我的 OpenCart table 排序规则是 utf8_bin,不幸的是我无法搜索名称中带有重音符号的产品名称。我在 Google 上搜索,发现排序规则必须是 utf8_general_ci 才能进行重音兼容和不区分大小写的搜索。

如果我在搜索查询中添加整理声明会怎么样?

SELECT * 
FROM  `address` 
COLLATE utf8_general_ci
LIMIT 0 , 30

它有任何(不良)副作用吗?我对索引、性能方面的问题很生气?还是完全安全?

using of COLLATE in SQL statements 中,我没有找到那个用法,无论如何,为了解释你使用归类的效果的主要问题,我找到了一些提示,但起初:

来自dev.mysql.com:

Nonbinary strings (as stored in the CHAR, VARCHAR, and TEXT data types) have a character set and collation. A given character set can have several collations, each of which defines a particular sorting and comparison order for the characters in the set.

  1. 归类仅仅是用于字符串比较的排序——它(几乎)与用于数据存储的字符编码无关。我说几乎是因为排序规则只能用于某些字符集,所以更改排序规则可能会强制更改字符编码。
    在字符编码被修改的范围内,MySQL 将正确地将值重新编码为新字符集,无论是从单字节到多字节还是反之。请注意,对于列来说太大的任何值都将被截断。[1]
  2. 二进制排序的实际优势在于它的速度,因为字符串比较非常 simple/fast。在一般情况下,二进制索引可能不会产生预期的排序结果,但对于精确匹配它们可能很有用。[2]
  3. 对于多个操作数,可能会出现歧义。例如:

    SELECT x FROM T WHERE x = 'Y';
    

    比较应该使用列 x 的排序规则还是字符串文字 'Y' 的排序规则? x'Y' 都有排序规则,那么哪个排序规则优先?
    标准 SQL 使用过去称为 “可强制性” 的规则来解决此类问题。 [3]

  4. 如果更改字段的排序规则,ORDER BY -[也在 WHERE]- 不能使用任何 INDEX;因此它的效率可能出奇地低。 [4]
  5. 由于强制排序规则是在与列编码相同的字符集上定义的,因此不会对性能产生任何影响(相对于将该排序规则定义为列的默认排序规则;而 utf8_general_ci 几乎肯定会执行得更慢在比较中比 utf8_bin 由于需要额外的 lookups/computation)。
    但是,如果强制使用在不同字符集上定义的排序规则,MySQL 将不得不转码列的值(这会影响性能)。[5]

如果可行,请更改列定义。

ALTER TABLE tbl
    MODIFY col VARCHAR(...) COLLATE utf8_general_ci ...;

(您应该包括列定义中已有的任何其他内容。)如果您有多个要修改的列,请在同一个 ALTER 中全部执行(为了速度)。

如果由于某种原因您无法执行 ALTER,那么可以调整 SELECT 来更改排序规则:

你说的SELECT没有过滤的WHERE子句,我改一下测试用例:

假设你有这个,它只会找到 'San Jose':

SELECT *
    FROM tbl
    WHERE city = 'San Jose'

包括San José:

SELECT *
    FROM tbl
    WHERE city COLLATE utf8_general_ci = 'San Jose'

如果您可能 "combining accents",请考虑使用 utf8_unicode_ci。 More on Combining Diacriticals and More on your topic.

至于副作用? None except for on potentially big one: 无法使用列上的索引。在我的第二个 SELECT(上图)中,INDEX(city) 是没有用的。 ALTER 避免了 SELECT 的这种性能损失,但是一次性 ALTER 本身是昂贵的。

恐怕你必须考虑对查询性能的副作用,尤其是那些使用索引的。这是一个简单的测试:

mysql> create table aaa (a1 varchar(100) collate latin1_general_ci, tot int);
insert into aaa values('test1',3) , ('test2',4), ('test5',5);

mysql> create index aindex on aaa (a1);
Query OK, 0 rows affected (0.59 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> desc aaa;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| a1    | varchar(100) | YES  | MUL | NULL    |       |
| tot   | int(11)      | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.53 sec)


mysql> explain select * from aaa where a1='test1' ;
+----+-------------+-------+------+---------------+--------+---------+-------+--
----+-----------------------+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | r
ows | Extra                 |
+----+-------------+-------+------+---------------+--------+---------+-------+--
----+-----------------------+
|  1 | SIMPLE      | aaa   | ref  | aindex        | aindex | 103     | const |
  1 | Using index condition |
+----+-------------+-------+------+---------------+--------+---------+-------+--
----+-----------------------+
1 row in set (0.13 sec)

mysql> explain select * from aaa where a1='test1' collate utf8_general_ci;
+----+-------------+-------+------+---------------+------+---------+------+-----
-+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows
 | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+-----
-+-------------+
|  1 | SIMPLE      | aaa   | ALL  | NULL          | NULL | NULL    | NULL |    3
 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+-----
-+-------------+
1 row in set (0.06 sec)

您可以看到,当您使用其他排序规则搜索 a1 时,MySQL 正在停止使用 a1 上的索引,这对您来说可能是个大问题。

为确保您的索引用于查询,您可能必须将列排序规则更改为最常用的排序规则。

这可能有帮助:UTF-8: General? Bin? Unicode? 请注意 utf8_bin 也区分大小写。所以我会去改变 table 归类为 utf8_general_ci 并为未来安心。