【问题标题】:How does MySQL use collations with indexes?MySQL 如何使用带有索引的排序规则?
【发布时间】:2009-03-12 02:11:40
【问题描述】:

我想知道 MySQL 在生成索引时是否考虑了排序规则,或者无论排序规则如何都生成相同的索引,只有在以后遍历该索引时才会考虑排序规则。

出于我的目的,我想在字段上使用排序规则 utf8_unicode_ci。我知道这个特定的排序规则有相对较高的性能损失,但使用它对我来说仍然很重要。

我在该字段上有一个索引,用于满足 ORDER BY 子句,快速按顺序检索行(避免文件排序)。但是,我不确定使用此排序规则是否会影响从索引中读回的行的速度,或者索引是否根据该排序规则将数据存储在已经标准化的状态,从而导致性能损失完全在生成索引而不是读回它。

【问题讨论】:

  • 你用索引做什么操作?订购?单键查找?范围查找?
  • 索引正用于 ORDER BY。谢谢

标签: mysql indexing


【解决方案1】:

我相信 btree 结构会有所不同,因为它必须以不同的方式比较列值。

看看这两个查询计划:

mysql> explain select * from sometable where keycol = '3';
+----+-------------+-------+------+---------------+---------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra                    |
+----+-------------+-------+------+---------------+---------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | pro   | ref  | PRIMARY       | PRIMARY | 66      | const |   34 | Using where; Using index | 
+----+-------------+-------+------+---------------+---------+---------+-------+------+--------------------------+


mysql> explain select * from sometable where binary keycol = '3';
+----+-------------+-------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | pro   | index | NULL          | PRIMARY | 132     | NULL | 14417 | Using where; Using index | 
+----+-------------+-------+-------+---------------+---------+---------+------+-------+--------------------------+

如果我们更改比较的排序规则,突然间它甚至无法再寻找索引,不得不扫描每一行。无论排序规则如何,存储在索引中的实际值都是相同的,例如,因为无论使用区分大小写还是不区分大小写排序规则,它仍将返回原始大小写中的值。

因此,针对不区分大小写的排序规则进行查找的效率应该会稍低一些。

但是,我怀疑您是否能够注意到其中的差异;请注意,默认情况下 MySQL 使所有内容不区分大小写,因此影响不会那么可怕。

更新:

您可以看到 order by 操作的类似效果:

mysql> explain select * from sometable order by keycol collate latin1_general_cs;
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows  | Extra                       |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------+
|  1 | SIMPLE      | pro   | index | NULL          | PRIMARY | 132     | NULL | 14417 | Using index; Using filesort | 
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-----------------------------+

mysql> explain select * from sometable order by keycol ;
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows  | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-------------+
|  1 | SIMPLE      | pro   | index | NULL          | PRIMARY | 132     | NULL | 14417 | Using index | 
+----+-------------+-------+-------+---------------+---------+---------+------+-------+-------------+

请注意执行查询所需的额外“文件排序”阶段。这意味着 mysql 将结果排队在一个临时缓冲区中,并在一个额外的阶段使用快速排序对其自身进行排序,丢弃任何索引顺序。使用原始排序规则这一步是不必要的,因为 mysql 最初知道索引中的顺序。

【讨论】:

  • 谢谢 - 所以如果我理解正确,即使保留了实际值,b-tree 中项目的排序也会受到排序规则的影响,所以 ORDER BY 仍然可以使用该排序规则时有效。如果我误解了,请告诉我。
  • 啊,我猜“使用文件排序”告诉了我需要知道的内容。那么该列的实际排序规则是否不区分大小写?我想此时我应该自己测试一下......
  • 是的。尝试使用 latin1_swedish_ci 和“COLLATE latin1_general_cs”的列排序规则,是的,它强制它进入文件排序。接受。
【解决方案2】:

MySQL 将使用列的排序规则作为索引。因此,如果您创建一个 utf8_unicode_ci 字段,那么索引也将有效地以 utf8_unicode_ci 顺序排列。

请记住,使用索引并不总是 100% 绕过性能影响,但对于大多数实际目的而言,它会。

许多数据库系统不受 CPU 限制,所以我怀疑您会注意到这种影响。

【讨论】:

  • 我假设,如果您想更改列排序规则,您还必须重新创建索引?
猜你喜欢
  • 1970-01-01
  • 2013-01-09
  • 2011-11-14
  • 2011-09-06
  • 1970-01-01
  • 2015-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多