Mysql - 索引

作者: 万福来 | 来源:发表于2020-04-01 17:50 被阅读0次

Mysql - 索引原理

索引目的

索引的目的在于提高查询效率,可以类比一本字典,如果要查询某个单词,可以先根据单词首字母查询字典目录,然后找到对应的页码,直接翻到指定页码在进行二分查找,提高查询效率。

磁盘IO与预读

磁盘IO是非常高昂的操作,计算机系统做了一些优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也会读取到内存缓冲区,这样可以方便计算机很快访问相邻的数据,这就是磁盘预读。每一次IO读取的数据称之为一页(page),page大小和操作系统有关,一般为4k或8k。

索引数据结构 B+Tree

为了每次查询数据的时候把磁盘IO次数控制在一个很小的数量级,我们需要一个高度可控的多路搜索树。这就是B+Tree。


image.png

浅蓝色为一个磁盘块,每个磁盘块包含几个数据项(深蓝色)和指针(黄色),如磁盘块1包含数据项17和35,包含指针P1、P2、P3表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块,真实的数据只存在于叶子节点。非叶子节点只存储指引搜索方向的数据项,而不存真实的数据。如17、35并不真实存在数据表中。

B+Tree的查找过程

比如要查找数据项29,需要先把磁盘块1加载到内存,发生一次IO,在内存中二分查找29在17和35之间,找到磁盘块1的P2指针;然后在通过P2指针在加载磁盘块3到内存,发生第二次IO,内存中二分查找29在26和30之间,锁定磁盘块3的P2指针;通过指针加载磁盘块8到内存,发生第三次IO,同时二分查找到29,结束查询,总计发生三次IO。

B+Tree性质

  • 一次查询发生IO的次数取决于B+Tree的高度h,假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则有h=log(m+1)N,树的高度就是log以m+1为底N的对数,如果m等于1时,也是一个二叉树!当数据量N一定的情况下,m越大则h越小;比如m=1、N=8则h=log(2)8=3;而m=磁盘块大小/数据项的大小;磁盘块大小就是数据页大小,一般为4K或8K,是固定的。所以数据项占空间越小,每个磁盘块存储的数据项就越多,树的高度就越低,查询发生的磁盘ID次数就越少。所以索引字段尽量要小,int占4字节,要比bigint8字节少一半。所以真实的数据要放到叶子节点,如果放在中间节点,会导致树增高。
  • 最左匹配特性,B+Tree是按照从左到右的顺序建立搜索树的,

联合索引数据结构

image.png

一个SQL只能利用到联合索引中的其中一列进行范围查找,因为B+Tree的每个叶子节点有一个指针指向下一个节点,把某一索引列的所有叶子节点串在了一起,只能根据单列的叶子节点进行范围查询。

Mysql - 索引原则

  • 最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如 a=1 and b=2 and c>3 and d=4 如果建立了(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a、b、d的顺序可以任意调整。
  • =和in可以乱序,比如 a=1 and b=2 and c=3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮助优化成索引可以识别的形式。
  • 尽量选择区分度高的列作为索引,区分度公式count(distinct col)/count(*),表示字段不重复的比例。
  • 索引列不能参与计算,否则索引会失效。
  • 尽量扩展索引,不要新建索引。

Mysql - 索引类型

索引主要分为两大类,聚簇索引和非聚簇索引

聚簇索引 (clustered index)

聚簇索引的叶子节点存储行记录,InnoDB必须要有且只有一个聚簇索引:

  1. 如果表定义了主键,则主键索引就是聚簇索引;
  2. 如果没有定义主键,则第一个非空的唯一索引列是聚簇索引;
  3. 如果没有唯一索引,则创建一个隐藏的row-id列作为聚簇索引。主键索引查询非常快,可以直接定位行记录。

非聚簇索引 (secondary index)

InnoDB非聚簇索引的叶子节点存储的是行记录的主键值,而MyISAM叶子节点存储的是行指针。
通常情况下,需要先遍历非聚簇索引获得聚簇索引的主键ID,然后在遍历聚簇索引获取对应行记录。
非聚簇索引需要扫描两遍索引树:又叫回表查询
1、先扫描非聚簇索引根据where条件定位到主键值id=9;
2、再根据主键ID扫描聚簇索引定位到行记录。

回表查询

回表查询就是先定位主键值,在根据主键值定位行记录,需要扫描两遍索引。
解决方案:
只需要在一颗索引树上能够获取SQL所需要的所有列数据,则无需回表查询,速度更快。
常见方法:
将要查询的字段,建立到联合索引里去,这就是索引覆盖
查询sql在进行explain解析时,Extra字段为Using Index时,则触发索引覆盖。
没有触发索引覆盖,发生了回表查询时,Extra字段为Using Index condition.

索引覆盖进行回表查询优化场景

select id, name, sex from table where name = 'tom'; #单列索引(name)联合索引(name,sex),可避免回表
select id, name, sex from table order by name limit 5 ,10 # 单列索引(name)联合索引(name,sex),可避免回表

索引条件下推 (Index Condition Pushdown)

mysql5.6引入了索引下推优化,默认开启,使用 SET optimizer_switch = 'index_condition_pushdown=off'; 可以关闭。
索引下推示例
数据库表中创建了联合索引 (a,b,c)
select * from table where a = 'a' and b like '%b%' and c like '%c%';
没有索引下推技术:
由于b和c使用了like,将导致索引匹配失效,所以只有a字段使用了索引,在索引中通过字段a查询到所有的数据,然后返回服务端,然后在服务端基于模糊匹配条件进行数据过滤。
使用索引下推技术:
可以在索引中首先通过字段a进行查询,然后在根据索引上的b和c判断是否符合模糊匹配条件,如果符合条件则根据该索引来定位对应数据,不符合则直接拒绝,有了索引下推技术,可以在有like条件的情况下减少回表次数,提高查询性能。

相关文章

  • MySQL索引及查询优化书目录

    MySQL索引的原理之索引目的 MySQL索引的原理之索引原理 MySQL索引的原理之索引的类型 MySQL索引的...

  • 高性能的索引策略

    MySQL查询基础-查询执行过程 MySQL聚簇索引 MySQL覆盖索引 MySQL索引扫描排序 MySQL冗余和...

  • MySQL索引的使用

    MySQL索引 MySQL索引可以快速提高MySQL的检索速度。索引分单列索引和组合索引单列索引:即一个索引只包含...

  • Mysql索引与锁

    本文以Mysql5.7为例测试。 1:mysql索引方法 Mysql的索引方法分为btree索引和hash索引。 ...

  • 索引(二)

    mysql索引的新手入门详解mysql索引之三:索引使用注意规则 索引(Index)是帮助 MySQL 高效获取数...

  • MySQL 索引分类

    MySQL索引的分类(根据数据结构) 索引的本质 MySQL官方对索引的定义为:索引(Index)是帮助MySQL...

  • MySQL--索引

    MySQL索引 查看索引 创建索引 创建唯一索引 创建主键索引 删除索引 删除主键 MySQL视图 创建视图 删除...

  • mysql索引

    索引 mysql索引的建立对于mysql的高效运行是很重要的,索引可以大大提高mysql的检索速度。索引分单列索引...

  • 5.2MySQL创建高性能索引考察点

    MySQL索引的基础和类型延伸:MySQL索引的创建原则延伸:MySQL索引的注意事项 索引的基础索引类似于书籍的...

  • MySql 数据查询优化

    1. MySQL索引类型: mysql的索引有5种:主键索引、普通索引、唯一索引、全文索引、聚合索引(多列索引)。...

网友评论

    本文标题:Mysql - 索引

    本文链接:https://www.haomeiwen.com/subject/cuiauhtx.html