MYSQL—索引总结(中)

MYSQL 的索引从应用层面可以分为,主键索引,唯一索引,联合索引。

主键索引:primary key  不允许有空值的唯一索引

唯一索引:unique key 必须唯一但是可以有空值

普通索引:key(a)

联合索引:key(a,b) 遵循最左前缀原则

1 索引长度为什么越短越好?

要了解这个问题,先了解一下磁盘IO/和预读。磁盘读取数据靠的是机械运动,每次读取数据花费的时间可以分为寻道时间、旋转延迟、传输时间三个部分,寻道时间指的是磁臂移动到指定磁道所需要的时间,主流磁盘一般在5ms以下;旋转延迟就是我们经常听说的磁盘转速,比如一个磁盘7200转,表示每分钟能转7200次,也就是说1秒钟能转120次,旋转延迟就是1/120/2 = 4.17ms;传输时间指的是从磁盘读出或将数据写入磁盘的时间,一般在零点几毫秒,相对于前两个时间可以忽略不计。那么访问一次磁盘的时间,即一次磁盘IO的时间约等于5+4.17 = 9ms左右,听起来还挺不错的,但要知道一台500 -MIPS的机器每秒可以执行5亿条指令,因为指令依靠的是电的性质,换句话说执行一次IO的时间可以执行40万条指令,数据库动辄十万百万乃至千万级数据,每次9毫秒的时间,显然是个灾难。

考虑到磁盘IO是非常高昂的操作,计算机操作系统做了一些优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,因为局部预读性原理告诉我们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。每一次IO读取的数据我们称之为一页(page)。具体一页有多大数据跟操作系统有关,一般为4k或8k(mysql一页是16K),也就是我们读取一页内的数据时候,实际上才发生了一次IO,这个理论对于索引的数据结构设计非常有帮助。

有了上面的基础做铺垫,我们再来聊下MYSQL索引的数据结构。这里我们只聊B+Tree的。

image.png

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。

两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。

以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】

比较关键字29在区间(17,35),找到磁盘块1的指针P2。内存时间因为非常短,可以忽略不计。

根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】

比较关键字29在区间(26,30),找到磁盘块3的指针P2。

根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】

在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。如果没有索引,每个数据项都要发生一次io,那么百万次io,显然成本非常高。

通过上面的分析,我们知道IO次数取决于b+数的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=㏒(m+1)N,当数据量N一定的情况下,m越大,h越小;

而m = 磁盘块的大小 / 数据项的大小,磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项占的空间越小,数据项的数量越多,树的高度越低。

这就是为什么每个数据项,即索引字段要尽量的小,比如int占4字节,要比bigint8字节少一半。

这也是为什么b+树要求把真实的数据放到叶子节点而不是内层节点,一旦放到内层节点,磁盘块的数据项会大幅度下降,导致树增高。当数据项等于1时将会退化成线性表

2 最左前缀原则是什么?

. 当b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+数是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道下一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。

那么这个联合索引根据最左匹配原则,可以在以下情况下利用到索引。

name

name age 

name age sex

而age sex 和 sex 是不会引用到索引的,

3 索引失效的场景都有哪些

最左匹配失效的时候

like 模糊匹配 前导有%的时候(like “%美女%”);

or 的两边有一边没有索引的时候

数据类型不匹配 类型隐式转化的时候  (整数与字符串比较 mysql是作为浮点数来比较的)

索引列上有函数,或者参与计算的时候(from_unixtime(create_time)=‘2019-07-12’,a+1=5)

!=,not in ,not exists 语句中,

索引最多用于一个范围列,因此如果查询条件中有两个范围列则无法全用到索引?

-- show full columns from t_base_user;

4 索引条件下推是什么

ICP index condition pushdown 

指的是MySQL在进行SELECT操作时,利用二级索引元组从表中提取数据的一种优化操作

其主要做法是MySQL的存储引擎在访问索引的时候,检查被筛选的字段在where语句中的索引条件(pushed index condition,也即从服务层被推送到存储引擎层的索引条件),如果元组中的数据不满足where条件则被过滤. 在explain的时候extra字段 可以看到using index condition;

ICP能减少引擎层访问基表的次数和MySQL Server 访问存储引擎的次数。

1 当sql需要全表访问时,ICP的优化策略可用于range, ref, eq_ref,  ref_or_null 类型的访问数据方法 。

2 支持InnoDB和MyISAM表。

3 ICP只能用于二级索引,不能用于主索引。

4 并非全部where条件都可以用ICP筛选。

   如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。

5 ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例。

6 5.6 版本的不支持分表的ICP 功能,5.7 版本的开始支持。

7 当sql 使用覆盖索引时,不支持ICP 优化方法。

5  回表是什么

在mysql进行搜索的时候,在索引上没法拿到想要的数据,然后需要根据索引再查找数据的过程叫回表。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注