关系型数据库索引设计与优化

本文基于mysql innodb引擎

请注意数据库DB2和MYSQL的聚簇索引和非聚簇索引的定义不同。

1、三星索引:

1、如果一个查询相关的索引行是相邻的,或者至少相距足够靠近,则索引可以被标记上第一颗星。(最小化了扫描的索引片的宽度)
2、如果索引行的顺序与查询语句的需求一致,则索引可以被标记上第二颗星。(避免了排序操作)
3、如果索引行包含查询语句中的所有列,则索引可以被标记第三颗星。(避免了回表)

简单理解:
1、where语句中的简单谓词和索引的顺序一致或相邻。
2、order by的最终结果和索引结果集的顺序一致。 
3、索引行包含所有查询字段。

案例分析:假设cno为主键,所以二级索引(非聚簇索引)叶子页键值中,值包含了cno不需要建立cno列为索引
select cno, fname from cust where lname between :lanme1 and :lname2 and city = :city order by fname

建立索引从第三颗星到第一颗星。
1、建立第三颗星(lname,city,fname)顺序不必在意,只需包含所有查询字段就可以。
2、建立第二颗星。如果fname在lname之后,那么索引结果集的顺序和需要的顺序不一致(例:记录1的个别字段为lname=b,fname=b。记录2的个别字段为lname=a,fname=a。则索引集顺序为1,2,但需要的顺序是2,1),所以fname必须在lname之前3、建立第一颗星。找到简单谓词city。所以第一个索引一定为city,fname不能为第一个因为这样的话,不能使用索引(最左匹配)。但要想满足第一颗星必须city和lname字段相邻,以满足最小的索引片。但city已经是第一个,并且fname必须在lname之前,
因此不能实现三星索引。那就只能在第一颗星和第二颗星之间做取舍。

候选A:(city, lname, fname)舍弃第二颗星,实现最窄的索引片,但无序。
1、取出等值谓词列,将这些列作为索引的最前列。(city)
2、如果有范围谓词,将选择性最好的范围谓词作为索引的下一个列,其他范围谓词加入其后。 (city, lname)
3、按照查询order by顺序添加order by(如果有desc,加上desc)列,忽略1.2步已添加的列。 (city, lname, fname)
4、将查询语句中剩余列,加入索引之后(以不易变的列开始)。(city, lname, fname)

候选B:(city, fname, lname)舍弃第一颗星,实现自排序,但索引片宽。 
1、取出等值谓词列,将这些列作为索引的最前列。 (city)
2、按照查询order by顺序添加order by(如果有desc,加上desc)列,忽略1.2步已添加的列。 (city, fname)
3、将查询语句中剩余列,加入索引之后(以不易变的列开始)。 (city, fname, lname)
具体使用A还是B,需要根据实际项目确定(一般第一颗星比第二颗星重要),或者bq
/qube算法。

2、索引设计与评估:

个人理解:《数据库索引设计与优化》一书中,其案例中的索引存储结构类似于mysql的myisam,索引和数据分开存储。索引叶子页只保存数据在表中的指针。

所以如果根据innodb的结构,就很难理解其第五章的qube案例。

一旦一个新的查询语句出现,那么就要考虑现有的索引对新的语句来说是否合适。那么如何判断呢?步骤如下:

对现有索引评估方法BQ:

基本问题法bq:
判断是否有一个已存在的索引包含了where子句中的所有列?
1:如果没有,首先考虑将缺少的谓词列添加到一个已有的索引上。这将产生一个半宽索引2:如果还没有达到足够的性能,那么将所有涉及的列都添加到索引上(除主键外),以避免回表。这将产生一个宽索引3:如果还没有达到性能要求,那么就要设计一个新的索引。

如何判断半宽索引宽索引的性能呢?
1:使用测试库进行测试
2:使用qube算法

对索引的评估方法QUBE:

快速上限估算法qube:
qube假设所有表、索引都是以最理想的顺序组织的。结果为最差输入情况下的响应时间。 响应时间对比公式 LRT
= TR * 10mx + TS * 0.01ms + F * 0.1ms 不同访问路劲对比公式 LRT = TR * 10mx + TS * 0.01ms LRT:本地响应时间 TR:随机访问的数量 TS:顺序访问的数量 F:有效fetch的数量

案例分析:假设姓名不重复
select cno, lname, fname, city from cust where lname = "张" and fname = ”飞"

索引A(lname, fname)
TR = 2(多一次回表), TS = 0, F = 1
LRT = TR * 10ms + TS * 0.01ms + F * 0.1ms = 20.1ms
索引B(lname, fname, city)最左匹配 TR = 1(覆盖索引), TS = 0, F = 1 
LRT = TR * 10ms + TS * 0.01ms + F * 0.1ms = 10.1ms
明显索引B更好。

 

posted @ 2021-01-07 15:35  无名之士  阅读(368)  评论(0编辑  收藏  举报