由于二叉查找树最坏情况下会变成线性的二叉树,时间复杂度由O(logn)变为O(n),故一般数据库索引的结构是B+Tree、Hash,我们先来介绍下B树。
B-Tree索引
定义
- 根结点至少包括两个孩子
- 树中每个节点最多含有m个孩子(m>=2)
- 除根结点和叶节点外,其他每个节点至少有ceil取上限(m/2)个孩子
- 所有叶子节点都在同一层
假设每个非终端节点中包含n个关键字信息,其中
- Ki(i=1..n)为关键字,且关键字按顺序升序排序K(i-1)<Ki
- 关键字的个数必须满足:[ceil(m/2)-1]<=n<=m-1
- 非叶子节点的指针:P[1],P[2]…P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其他P[i]指向关键字属于(K[i-1],K[i])的子树
B+-Tree索引
B+树是B树的变体,其定义基本与B树相同,除了
- 非叶子节点的子树指针与关键字个数相同
- 非叶子节点的子树指针P[i],指向关键字[K[i],K[i+1]]的子树
- 非叶子节点仅用来索引,数据都保存在叶子节点中
- 所有叶子节点均有一个链指针指向下一个叶子节点
B+Tree更适合用来做存数索引
- B+树的磁盘读写代价更低
- B+树的查询效率更加稳定
- B+树更有利于对数据库的扫描
Hash索引
Hash结构可以直接根据key取到value,查询效率高,但是Hash索引也有一下缺点
- 仅仅能满足 = IN,不能使用范围查询
- 无法被用来避免数据的排序操作
- 不能利用部分索引键查询
- 不能避免表扫描
- 遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高
索引模块(T)
:memo: 为什么要使用索引
使用索引可以避免全表扫描,提高检索效率。
:memo:什么样的信息能成为索引
主键唯一键等,能让数据具备一定区分性的字段。
:memo:索引的数据结构
B+树,Hash,BigMap,MySQL不支持BigMap,Innodb和MyISAM不显式支持Hash。
:memo: 密集索引和稀疏索引的区别
- 密集索引文件中的每个搜索码值都对应一个索引值
- 稀疏索引文件只为索引码的某些值建立索引项
MyISAM不管是主键索引、唯一键索引或者普通索引,其索引均属于稀疏索引,而InnoDB有且只有一个密集索引
- 若一个主键被定义,该主键则作为密集索引
- 若没有主键被定义,该表的第一个唯一非空索引则作为密集所以
- 若不满足以上条件,innodb内部会生成一个隐藏主键(密集索引)
- 非主键索引存储相关键位和其对应的主键值,包含两次查找
索引衍生问题,MySQL为例(T)
:memo:如何定位并优化慢查询Sql
1.根据慢日志定位慢查询sql
1 | show variables like '%quer%'; #1.查询变量 |
2.使用explain等工具分析sql
1 | explain关键字段 |
3.修改sql或者尽量让sql走索引
1 | EXPLAIN SELECT shop_price FROM product ORDER BY shop_price DESC; #extra是Using filesort |
:memo:联合索引的最左匹配原则的成因
- 最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>,<,between,like)就停止匹配,比如a=3 and b=4 and c>5 and d=6 如果建立(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的查询优化器会帮你优化成索引可以识别的形式
- 联合索引的最左匹配原则的成因:mysql创建复合索引的规则是首先会对复合索引的最左边,也就是索引中的第一个字段进行排序,在第一个字段排序的基础上,在对索引上第二个字段进行排序,其实就像是实现类似order by 字段1,字段2这样的排序规则,那么第一个字段是绝对有序的,而第二个字段就是无序的了,因此一般情况下直接只用第二个字段判断是用不到索引的,这就是为什么mysql要强调联合索引最左匹配原则的原因。
:memo:索引是建立得越多越好吗
- 数据量小的表不需要建立索引,建立会增加额外的索引开销
- 数据变更需要维护索引,意味着更多的索引意味着更多的维护成本
- 更多的索引也需要跟多的存储空间