如何发现及替换不合适的索引

这是数据库索引相关内容的第五篇
复制代码

发现不合适的索引

触发咱们考虑考虑索引是否合适的契机有两种数据库

一种是:生产环境中出现查询慢,咱们急于解决现实遇到的问题;

一种是:在设计实现阶段,咱们但愿提早发现设计不合理的索引,以避免后续发布之后才出现性能问题;
复制代码


对于 \color{red}{第一种} 状况,咱们能够经过提问来反思如何改进索引。post

1. 是否全部where子句中的全部列都在索引中了?性能

      若是没有,则添加到索引中,将索引变成半宽索引优化

2. 是否将全部涉及的列都加入到索引中了?spa

      若是变成半宽索引后,仍是没有解决到性能问题,那么下一个选择就是将查询中全部涉及的列都加入到索引中,造成宽索引;这样,优化器的访问只需访问索引,避免了表访问。设计

3. 你须要最佳索引code

      若是上述两种方式,仍未解决性能问题,则要参考《什么是最好的索引》一文,好好考虑一下索引的设计了索引

      例如:SELECT A FROM XXX WHERE B = 1 AND C = 2;而索引是(A, B, C) 按照《索引》中的优化器逻辑,其索引片是空,即其查询将进行全索引扫描;若是索引超过10w条记录,那么查询将会很慢get

      可是按照上述的检查方式,第一条和第二条其都是知足的,可是该索引在必定的数量级下依然会致使查询效率慢,那么就要作第三步,对索引进行从新考虑了。io

在正式运行的系统中,建议扩充索引列,而不是新增新的索引或者更换索引列的顺序,和将带来额外的负担。



对于 \color{red}{第二种} 状况,咱们能够经过系统的评估来查看索引是否合适。

1. 统计本地相应时间

      直接先上结论:

      本地响应时间(LRT) = 随机访问的数量(TR) * 10ms + 顺序访问数量(TS) * 0.01ms + 有效FETCH数量(F) * 0.1ms

      什么是随机访问:就是一次磁盘IO的时间,约为10ms
      什么是顺序访问:一页包含n行,每行的时间约为0.01ms;

      再详细一点:
      DBMS读取一个索引或一个表行的成本,即为一次访问;
      DBMS扫描索引或表的一个片断,其中第一行的读取即为一次随机访问;
      对于后续行的读取,每行都是一次顺序访问;

      打个比方:
      对于去超市买10个罐头:
      随机访问就比如在超市找到罐头的货架的时间,就是10ms
      顺序访问就比如已经找到罐头的货架了,只要一个个把罐头拿下来,每一个罐头的时间就是0.01ms

      好了,知道了随机访问和顺序访问,接下来咱们知道如何肯定随机访问和顺序访问的次数

索引访问次数

      能够将索引当成一张表,其行数与其包含的表的行数相同,且按照索引键值排列

表访问次数

      咱们假设一次全表扫描将须要一次随机访问和N-1次顺序访问


2.举例

\color{purple}{2.1 主键索引}

主键索引:select CNAME, CNO, CDESC from table1 where CNO = 221
其中CNO为主键;

索引存储以下:
111,
112,
113
...
221,
222

那么优化器是如何检索的?
i. 根据CNO=221,进行一次随机访问,取到221这条索引
ii. 根据221这条索引指向的磁盘位置,经过一次随机访问,找到数据块,获得CNAME,CDESC

那么LRT是多少?
很好计算: 两次随机访问 + 1次FETCH = 2 * 10ms + 0.1ms 约等于 20ms


\color{purple}{2.2 聚簇索引}

select CNO, CNAME, CDESC from table1 where CTYPE = 1 and CNAME = 'ZHANG' order by CDESC

假设索引是(CTYPE, CNAME, CDESC) 假设CTYPE =1 和CNAME='ZHANG'能从10w的索引中过滤出1000条

1000条索引以下:
1,'ZHANG', 1
1,'ZHANG', 2
....
1,'ZHANG', 1000

那么LRT是多少?
首先,一次随机访问索引的时间,定位到索引1000条的第一行
其次, 1000次顺序访问索引的时间
而后,因CNO不在索引中,因此还须要经过索引进行磁盘查找;
由于是聚簇索引,因此表的顺序和索引的顺序是一致的,访问表的时间和索引是同样的,即一次随机访问表的时间,和1000次顺序访问的时间(999很差计算,咱们都约等于1000)

LRT= 1次索引随机访问 + 1000次索引顺序访问 + 1次表随机访问 + 1000次表顺序访问 + 1000次FETCH
      = 10ms + 1000 * 0.01ms + 10ms + 1000 * 0.01ms + 1000 * 0.1ms
      = 140ms

\color{purple}{2.3 非聚簇索引}

同2.2 ,若是一样是该查询语句,可是索引变成非聚簇索引会怎么样?

很显然,表的存储会发生变化,再也不是跟索引的顺序一致,而且不是连续存储了;

因此,

LRT = 1次索引随机访问 + 1000次索引顺序访问 + 1000次表随机访问 + 1000次FETCH
      = 10ms + 1000 * 0.01ms + 1000 * 10ms + 1000 * 0.1ms
      = 10s(约等于)

你看,一样的1000条索引,查询速度和2.2相差这么多!

这个索引该如何优化呢,很显然,若是它不是聚簇索引,就要将CNO归入到索引中来,避免表的随机访问;将全部的访问都回到索引内部

\color{red}{CTYPE, CNAME, CDESC,CNO}

很显然,这就是《什么索引是好的索引》中介绍的所谓的好的索引,知识都是相辅相成的。

使用了该更改后的索引,其LRT会变成多少?

LRT = 10ms + 1000 * 0.01ms + 1000 * 0.1ms = 120ms

速度提高了100倍!



好了,本文重点介绍了如何在实际生产环境中和设计过程当中发现问题及优化索引,只要掌握原则,了解思路,剩下的就是运用了。


其余相关章节
复制代码

数据库索引相关文章之一:《B树,一点都不神秘》
数据库索引相关文章之二:《B树很简单,插入so easy》
数据库索引相关文章之三:《索引》
数据库索引相关文章之四:《什么索引算是好的索引》
数据库索引相关文章之五:《如何发现及替换不合适的索引》
数据库索引相关文章之六:《索引总结》

相关文章
相关标签/搜索