学习Mysql性能优化-索引一节的总结,非常适合初学者和一些对索引知识认识不够系统的人学习。由于相关图片资源无法直接转存到CSDN,就不单独处理了,直接贴一下有道云笔记外部地址。欢迎点评和评论,共同成长!
http://note.youdao.com/noteshare?id=5d27ff2f8a96c6cf03bcf8a3fc851063
第一节、深入浅出的认识Mysql索引
写在前面的话
正确的创建合适的索引,是提升数据库查询性能的基础
一、Mysql体系结构图
二、认识索引
1、索引是什么
索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构。
2、为什么要用索引
- 索引能极大的减少存储引擎需要扫描的数据量
- 索引可以把随机IO变成顺序IO
- 索引可以帮助我们在进行分组、排序等操作时,避免使用临时表
三、为什么选择B+Tree
1、二叉查找树
缺点:层次太深,极端情况可能出现链表的情况,时间复杂度O(logn)-O(n)
2、平衡二叉查找树
关键字:索引列上对应的值
数据区:存放磁盘物理数据或者物理数据的磁盘地址
子节点引用:指向下一子节点的地址
缺点:
- 它太深了。数据处的(高)深度决定了它的IO次数,IO操作耗时大
- 它太小了。
- 每一个磁盘块(节点/页)保存的数据量太小了。(操作系统默认每次从磁盘交换一页(通常为4K)的数据到内存)
- 无法很好的利用操作磁盘IO的数据交换特性,也没有很好的利用磁盘IO的预读能力(空间局部性原理),从而带来频繁的IO操作
通俗的话解释“空间局部性原理”,当向磁盘交换某个地址的数据时,操作系统会认为马上可能会用到上一页/下一页的数据,会提前预加载,所以每次交换的数据往往不只一页
3、多路平衡查找树
计算公式:
- N = (16*1024-Z)/(X+Y+Z)
- M = N+1
Mysql默认每页数据大小为16K,1K=1024Byte
N:节点存储关键字的数量
X:单个关键字存储所占物理空间大小
Y:单个数据区存储所占物理空间大小
Z:单个子节点引用存储所占物理空间大小
M:平衡查找树的宽度(路数)
参考举例:假设我们采用int类型的id列作为索引,int类型的值占用4byte长度的大小,将单个数据区和子节点引用所占物理空间大小约等于4byte,那么粗略计算出N约等于2000,每个节点可以保存2000关键字的数量,将大大降低树的深(高)度。
优点:
- 天然的是绝对平衡树(数据插入到叶子节点,不平横时向上提升)
- “矮胖型”的树降低了树的深(高)度
- 每个节点保存的数据更大,很好的利用空间局部性原理
4、Mysql选择的B+树
B树与B+树的区别:
- B+树节点关键字搜索采用闭合区间(每个节点搜索都需要搜索到叶子节点)
- B+树非叶节点不保存数据相关信息,只保存关键字和子节点的引用(能够存放关键字的数量更多,Mysql中默认每页加载数据大小16K,索引字段占用越小,数据区越小(B+树非叶子节点不保存数据),可以使得整棵树更加“矮胖”,树的深(高)度越浅(低),检索时间复杂度越低,这也是为什么表定义字段时建议索引字段长度能给小尽量给小)
- B+关键字对应的数据保存在叶子节点中(数据存储更加集中,相邻数据集中了更多顺序IO)
- B+叶子节点是顺序排列的,并且相邻节点具有顺序引用的关系(数据存储天然自带排序)
选择B+树的优势
- B+树是B-树(B树)的一个增强版(多路绝对平衡查找树),同样具备B-树的优势
- B+树扫库、表能力更强(只需要扫叶子节点)
- B+树的磁盘读写能力更强(更多的顺序IO)
- B+树的排序能力更强(数据存储默认按照索引关键字有序)
- B+树的查询效率更加稳定(仁者见仁、智者见智。B树搜索节点存在不确定性,可能在根节点、中间节点、叶子节点,如果树的深(高)度很深(高),检索到节点关键字所耗时差异较大。而B+树每次检索数据都需要检索到叶子节点)
四、Mysql B+Tree索引体现形式
1、各种存储引擎在Mysql中数据存储文件
.frm存储表定义文件。每种存储引擎都有的一个表定义(创建表的语句,字段及字段大小、字段约束等等)文件。
Mysql存储引擎是提供一套原子API方式,具体交给第三方实现,通过插拔式适配到Mysql中,作用于表<每个表都可以选择不同的存储引擎,在创建表时可显示指定存储引擎>,后续文章再对各大存储引擎做详细介绍。
MyISAM存储引擎(Mysql5.5版本之前默认的存储引擎)
- .MYI存储表索引
- .MYD存储表数据
InnoDB存储引擎(Mysql5.5版本之后默认的存储引擎)
- .idb存储表索引及表数据文件(聚集索引/聚簇索引)
MEMORY存储引擎
- 数据存储在内存中。Mysql中临时表所采用的存储引擎,默认单表数据最大16M,超过则选择MyISAM引擎
MERGE存储引擎
- 是一组MyISAM表组合
ARCHIVE存储引擎
- .ARZ采用压缩的方式存储表数据文件(提供参考数据:MyISAM引擎中单表数据100万,占用空间大小104M,在ARCHIVE引擎同样的数据占用磁盘空间3M)
2、B+Tree在MyISAM中体现形式
特点:
- 索引之间关系平等(没有物理的主辅关系)
- 索引和数据单独存储,划分明确,容易理解
- 节点数据区保存数据的物理磁盘地址
3、B+Tree在InnoDB中体现形式
特点:
- 采用聚集索引存储索引和数据文件
- 辅助索引叶子节点存储主键索引的关键字
- 当表未定义主键时,使用唯一索引作为主键索引,当未定义主键和唯一索引时,会默认生成6byte的自增数字id(隐藏)作为主键索引,InnoDB认为主键是非常重要且常用的检索数据条件
4、MyISAM和InnoDB对比
四、索引知识补充
1、列的离散性(重复度)
答案:name>zoneDesc>sex
计算公式:count(distinct col):count(col) 不重复的数量/总数
结论:列的离散性越高,选择性就越好。sql优化器在检索数据时发现离散性很差时,可能会选择全表扫描,创建索引时尽量选择离散性高的列(字段)作为索引
2、最左匹配原则
3、联合索引
往往实践中设计联合索引时原则是:最常用优先>离散性高优先>宽度小优先
场景实践:
通过最左匹配原则,当通过name字段检索时同样可命中联合索引,此时单独创建name字段作为索引是冗余的表现,减少冗余索引的设计,可提高DML语句的效率
select * from user where phoneNum=‘1378’ and username='李二狗'不会命中索引
4、覆盖索引
如果查询列可通过索引节点中的关键字直接返回,则该索引称之为覆盖索引。
- 通俗的话解释就是查询的字段就是索引关键字,此时可直接返回索引关键字而不用检索到叶子节点。
覆盖索引可减少数据库IO,将随机IO变为顺序IO,可提高查询效率。
通过上例我们发现:select name,phoneNum from user where name='李二狗' and phoneNum=‘1378’;此时就可能命中覆盖索引,如果是select * from user where username='李二狗'此时就一定不会命中覆盖索引,所以很多实际场景和公司禁止使用 “*”作为查询字段,比如58同城的“58条军规”就严令禁止。
5、知识运用和总结
- 索引列的字段长度能少则少
- 索引不是越多越好,越全越好,一定是建立合适的索引
- 匹配列前缀可能用到索引 like 999%(离散性差时也会全表扫描),like %99%、like %999用不到索引
- WHERE条件中not in 和<>(!=) 操作无法使用索引
- 匹配范围值,order by也可能用到索引
- 多用指定列查询,只返回自己想要的数据列,少用select *(根据实际场景)
- 联合索引中如果不是按照索引最左列开始查找,无法使用索引
- 联合索引中精确匹配最左前列并范围匹配另外一列时可以用到索引
- 联合索引中如果查询中有某个列的范围查询,则其右边的所有列都无法使用索引
最后总结成一首打油诗献给大家:
全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
LIKE百分写最右,覆盖索引不写星;
不等空值还有OR,索引失效要少用。