读薄《高性能MySql》(三)索引优化 (2)

可以把相关数据保存在一起,比如按照用户 id 取邮件,因为邮件都根据 id 保存在一个地方,所以只需要比较少次 I/O就可以把同一个用户的全部邮件读取完。

#4.2 聚簇索引缺点

聚簇数据查询顺序依赖于插入顺序,按照主键顺序插入是最快的,如果不是按照主键顺序插入,在插入后最好用 OPTIMIZE TABLE 重新组织一下表。

更新聚簇索引列的代价很高,因为每个更新的行都要移动到新位置。

需要插入行或者移动行的时候可能会产生碎片,会占用更多空间。

聚簇索引会导致全表扫描变慢,由于页分裂会导致数据存储不连续

#4.3 避免随机插入

最好避免随机的聚簇索引,这种情况下还不如使用一个和业务无关的自增列。特别是对于 I/O 密集操作,因为随机索引插入,这会导致页分裂并且需要移动列的位置。

#5 高性能索引 #5.1 查询中索引不要带表达式

查询条件中,索引不能是表达式的一部分,也不能是函数的参数,MySql 并不会懂得去优化它,比如说下面的选择。

SELECT id from singer where id + 1 = 5

我们很容易看出来这个表达式等价于查找 id 为 4 的歌手,但是 MySql 不懂得自己去优化它,不会使用到索引,而是采用全表搜索。

#5.2 选择合适索引前缀长度

我们首先引入个概念

索引的选择性:通俗地说就是索引对列的区分度,比如说如果每一个列有唯一的 id,那么选择性就是 1,如果有 100 个相同的 id,那么选择性就是 1 / 100,索引的选择性越高性能越好。

有时候索引需要很长的字符串,这些索引会让查询变得很慢,一个解决策略就是前面说到的手动创建哈希索引。另外一种方法就是只使用前面几个字符来作为索引,但是这样会降低索引的选择性。诀窍在于要使用刚刚好长度的字符串前缀作为索引,索引太长会导致一次性读入内存的索引减少,太短会导致区分度不高,B+ 树查找完索引还要线性查找很长一段距离。

为了更直观的解释如何选择合适的长度,我们拿一张表来举个例子

song(id, title)

歌曲表,里面有 id 和 标题,我们的目标是在 title 上创建索引。

为了直观的看出索引的区分度,我们可以用一些 SQL 语句来测试数据,逐渐增加前缀的长度,选择最适合的长度。

SELECT COUNT(*) AS cnt , LEFT(title,3) AS pref FROM song GROUP BY pref ORDER BY cnt DESC LIMIT 10;

选择结果如下

(https://img2018.cnblogs.com/blog/1215522/201811/1215522-20181128210523671-1840111696.png)

我们只看数值最大的那个,因为如果第一个数值很大,那么查询这个前缀的时候效率会变得很低,我们可以慢慢增加前缀长度直到数字达到可以接受的数值。

当然也可以计算一个查询的前缀长度的选择性

SELECT COUNT(DISTINCT LEFT(title, 3))/COUNT(*) AS sel3, COUNT(DISTINCT LEFT(title, 4))/COUNT(*) AS sel4, COUNT(DISTINCT LEFT(title, 5))/COUNT(*) AS sel5 FROM song;

(https://img2018.cnblogs.com/blog/1215522/201811/1215522-20181128210536804-1253539391.png)

这个值越大查询效率越高,一般来说,可以慢慢增加前缀直到这个数值增加的不明显为止,然后根据具体需求选择出合适的长度。

#5.3 避免多列索引

在上一节的例子中,有人可能会创建这样的索引。

key(名),key(姓),key(生日)

这样运行下面这个查询的时候,可能用不到这个索引。

SELECT * FROM student WHERE 名='宁' AND 姓='宁'

对于这样的查询,这个索引

key(姓,名)

会更合适

在 MySql 5.0 和更新版本中,查询能同时使用两个索引进行扫描,并将结果合并(这就用到了这 key(姓)和 key(名) 这两个索引)。索引合并是一项优化策略,但是更可能说明了索引创建的很糟糕。

当出现了多个 AND 关联的查询,应该采用包含所有类的索引而不是独立的单个索引。

key(姓, 名)

#5.4 选择合适的索引列顺序

从前面讲到的索引限制条件,我们可以知道,一个好的索引顺序能极大的提高索引的利用率。

当不需要排序和分组的时候,将选择性最高的列放在前面通常是很好的选择,这是一种经验法则。但是这和值的分布有关,也和业务有关,没有一个四海皆准的法则。

一个比较有效的方法就是提取出比较差的查询,然后按照选择率来创建索引,将选择性高的列放在索引左边创建索引。

#5.5 索引覆盖

当使用到的索引就是需要的值,那么就能减少磁盘的 IO,查询效率大大提升。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwppys.html