MySQL总结-索引

目录

目标

数据结构

索引类型

索引用途

时间与空间的考虑

更好的创建索引

ICP

索引使用


目标

对mysql的学习总结,我会从执行引擎、索引、sql、锁、MVCC、事务等几个部分进行阐述。本节阐述索引,包括索引采用的数据结构、如何更好的创建索引、索引使用的注意事项等。

数据结构

mysql各种索引都采用B+Tree数据结构

为什么选择B+树,而不是B树?

考虑磁盘IO消耗低,查找效率更稳定等等。

B树(B-树)

    每个节点都存储具体数据,从而块中可存记录变少,导致磁盘IO增多,树高度增加。
    命中可能发生在任意节点,查找的效率不稳定

B+树

    只有叶子节点存储具体数据,其它节点只存储key和指针,从而块中记录增多,树高度降低,同样大小的内存可缓存更多的节点,磁盘IO也减少。
    命中只发生在叶子节点,查找效果稳定。

磁盘IO什么时候发生?

需要读取的数据未缓存到内存中。

树的数据结构

结构图示

聚族索引结构+二级索引(非聚簇索引)结构图示

MySQL总结-索引_第1张图片

如图可见:

表存在主键时:聚簇索引=主键索引

二级索引的叶子结点数据包括 索引内容与主键ID。

二级索引命中主键ID后,使用主键ID查询主键索引命中记录。 

 

其他

树的高度=索引的高度

索引的高度影响查询效率,建议索引高度控制在3层以内,表数据量控制在1千5百万左右。

 

索引类型

InnerDB的聚簇索引

    仅限InnerDB引擎

    聚集原则

        1:存在主键,则主键构建聚簇索引
        2:不存在主键,则第一个不允许NULL的唯一索引构建为聚簇索引
        3:均不满足,则使用rowid构建聚簇索引。

    特点

        索引节点+数据节点,构成了数据叶子节点。
        一个文件:索引文件+数据文件。
        通过索引获取数据不需要再次磁盘寻址。

MyIsam的非聚簇索引

    MyIsam引擎

    特点

        索引叶子节点存储的数据为:记录在磁盘中的位置
        两个文件:索引文件,数据文件
        通过索引获取数据在磁盘的位置,然后磁盘寻址并获取数据。

二级索引

    不作为上述索引的其它索引,均为二级索引。
    叶子节点:索引数据+对应的(非)聚族索引数据,例如:索引数据+ID

 

索引用途

影响读

    1:快速查询
    2:如果where所有条件满足最左匹配,且索引包含了所有select中字段,则从索引中直接取出select字段数据
    2:如果where所有条件满足最左匹配,且索引包含了所有order by中字段,且order by列不在where但符合最左匹配,则直接使用索引中字段进行排序

        
影响锁

    从锁实现原理,加锁情景理解,导致聚族索引/甚至二级索引都被加锁。        

 

时间与空间的考虑

情景

从用途可以得出,当索引中字段足够多时,可以直接从索引中获取,而省去了读取数据节点,从该角度理解:查询速度会更快。

思考

结合 索引节点大小,page,索引深度,上述做法使得索引节点很大,索引深度增加,导致查找次数增多,可能导致更多磁盘IO

结果

索引变大,但查询速度未必提升。空间和时间应该合理考虑。

 

更好的创建索引

考虑sql

    针对使用最频繁的sql,创建索引

索引列的选择性

哪些列适合建组合索引

        如果一组列条件从表中扫描的数据量占总量的比例很小(一般5%甚至1%以下,千万级别的表最好在0.1%以下),这些列可以作为组合索引。

组合索引列的NDV

        要求扫描的数据行少,就要求条件列组合能过滤掉大量的数据,即为列组合的NDV(number distinct value 不重复数据量)很高。
        show indexes from table
可查看索引各列的基数Cardinality, 可大致表示NDV.

选择性

        列的选择性=(Cardinality)列的基数/(total)表记录总数。选择性越高,索引的作用越大。

举例
            MySQL总结-索引_第2张图片

         由图可知

            虽然NDV和cardinality数据存在差异,但均能表达出列的是否适合做为索引。
            status和biz_type的选择性太低了,扫描行会很多,不适合做索引。
            buyer_id和pay_timeNDV很大,扫描行会较少,适合做索引。

建议

将选择性最高的列放到索引首列,选择性越高越应该放到前边。

或者与查询频率很高的列进行组合。

考虑索引的高度

索引字段类型大小 直接影响 索引高度。

索引高度与磁盘IO次数的关系(暂不考虑内存cache):

聚族索引(如主键)查找记录的理论IO次数与聚族索引高度有关;

非聚族索引查找记录的理论IO次数=非聚族索引查找次数+聚族索引查找次数。

计算索引高度

    准备已知条件

        mysql中page大小=16K
        page使用最大比例:70%
        指针大小=8byte
        聚族索引字段类型大小
        二级索引字段类型大小
        记录行大小估值

    举例:
        聚族索引字段大小:4byte
        二级索引字段大小:4byte
        记录行大小:200byte

    计算过程:

        一个page可存聚族索引叶子节点数
            page大小 * page最大使用率 / (行记录大小+聚族索引字段大小)
            16384(page大小)*70% /200(聚族索引字段大小4相对200太小,被省略了) 约等于 50

        一个page可存储非聚族索引的节点数
            page大小 * page最大使用率 / (指针大小+非聚族索引字段大小)
            16384*70% / (8+4) 约等于 1000

        计算索引高度与行数的关系
            索引高度为2,则聚族索引可存记录数=1000*50=5W,则非聚族索引节点数=1000*1000=100W
            索引高度为3,则聚族索引可存记录数1000^2*50=5KW,非聚族索引节点数=1000^3=10亿

    若已知记录数A,索引大小B;则A不变时,B越大,索引高度越大,使用的page就越多,可能磁盘IO就越多。

    总结

        单表索引高度最好<=3
        索引字段越大,索引高度就越大,从而降低索引查找效率,导致sql性能降低。

索引的使用成本

    空间成本
        当表很大且索引字段较多时,索引占据的磁盘空间也会很大。

    时间成本
        索引使用不好,查询效率很低。
        从扫描行数返回行数考虑,索引使用不好,导致引擎的扫描行很多,即返回的记录数很多,然后在mysql server层进行filter,得到返回行,这样效率低下。

    更新成本
        更新记录时,也需要更新二级索引。当二级索引较多时,造成更新成本增加。

 

ICP

概念

    ICP  index condition pushdown 索引条件过滤下推,官网地址。
    扫描行:引擎使用命中的索引字段查找并返回的记录行数
    返回行:mysql server使用where中其它条件进行过滤后的记录行数

ICP做的事

server将where过滤下推到引擎中,索引过滤后,使用where过滤。

ICP的意义

    减少回表的次数,减少IO次数,减少server过滤记录数,降低时间成本。
    减少DML走二级索引时加锁的范围和时间,降低阻塞和死锁的发生。

 ICP的使用条件

    只适用于二级索引
    只适用于单表查询,不适用于关联查询
    只适用如下索引操作类型:EQ_REF/REF_OR_NULL/REF/SYSTEM/CONST
    只能时RANGE操作,其它都不行,如ALL/FT/INDEX_MERGE/INDEX_SCAN

 

索引使用

匹配原则

    最左匹配原则,要求必须是精确查询,>=< >= <= between and  in

无法使用索引列的情况

    类型转换
    使用表达式
    使用函数
    模糊查询 like
    不符合最左规则

组合索引使用建议

    按照最左匹配的列越多,数据越精确,则速度越快;反之,速度越慢;
    让条件尽可能的具体,使扫描行与返回行更加接近;

其他

DML操作最好使用聚族索引,因为使用二级索引的话,会在二级索引和聚族索引都加锁,导致扩大了锁的范围。

 

 

 

 

 

 

你可能感兴趣的:(MySQL)