这是数据库索引相关内容的第五篇
复制代码
触发咱们考虑考虑索引是否合适的契机有两种数据库
一种是:生产环境中出现查询慢,咱们急于解决现实遇到的问题;
一种是:在设计实现阶段,咱们但愿提早发现设计不合理的索引,以避免后续发布之后才出现性能问题;
复制代码
对于 状况,咱们能够经过提问来反思如何改进索引。post
1. 是否全部where子句中的全部列都在索引中了?性能
若是没有,则添加到索引中,将索引变成半宽索引优化
2. 是否将全部涉及的列都加入到索引中了?spa
若是变成半宽索引后,仍是没有解决到性能问题,那么下一个选择就是将查询中全部涉及的列都加入到索引中,造成宽索引;这样,优化器的访问只需访问索引,避免了表访问。设计
3. 你须要最佳索引code
若是上述两种方式,仍未解决性能问题,则要参考《什么是最好的索引》一文,好好考虑一下索引的设计了索引
例如:SELECT A FROM XXX WHERE B = 1 AND C = 2;而索引是(A, B, C) 按照《索引》中的优化器逻辑,其索引片是空,即其查询将进行全索引扫描;若是索引超过10w条记录,那么查询将会很慢get
可是按照上述的检查方式,第一条和第二条其都是知足的,可是该索引在必定的数量级下依然会致使查询效率慢,那么就要作第三步,对索引进行从新考虑了。io
在正式运行的系统中,建议扩充索引列,而不是新增新的索引或者更换索引列的顺序,和将带来额外的负担。
对于 状况,咱们能够经过系统的评估来查看索引是否合适。
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.举例:
主键索引: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
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
同2.2 ,若是一样是该查询语句,可是索引变成非聚簇索引会怎么样?
很显然,表的存储会发生变化,再也不是跟索引的顺序一致,而且不是连续存储了;
因此,
LRT = 1次索引随机访问 + 1000次索引顺序访问 + 1000次表随机访问 + 1000次FETCH
= 10ms + 1000 * 0.01ms + 1000 * 10ms + 1000 * 0.1ms
= 10s(约等于)
你看,一样的1000条索引,查询速度和2.2相差这么多!
这个索引该如何优化呢,很显然,若是它不是聚簇索引,就要将CNO归入到索引中来,避免表的随机访问;将全部的访问都回到索引内部
很显然,这就是《什么索引是好的索引》中介绍的所谓的好的索引,知识都是相辅相成的。
使用了该更改后的索引,其LRT会变成多少?
LRT = 10ms + 1000 * 0.01ms + 1000 * 0.1ms = 120ms
速度提高了100倍!
其余相关章节
复制代码
数据库索引相关文章之一:《B树,一点都不神秘》
数据库索引相关文章之二:《B树很简单,插入so easy》
数据库索引相关文章之三:《索引》
数据库索引相关文章之四:《什么索引算是好的索引》
数据库索引相关文章之五:《如何发现及替换不合适的索引》
数据库索引相关文章之六:《索引总结》