索引的定义,及数据结构的选用:
mysql索引,就是帮助提高检索效率的排好序的数据结构;
如果没有索引,就需要全表扫描,每次都加载几页数据到内存,然后进行内存数据对比。
全表扫描缺点:1磁盘io次数多;
2 内存数据无序,对比效率低。
针对这种情况,有序的树结构就可以很好的优化这2种情况,备用数据结构:二叉树,红黑树,b树,b+树。
- 二叉树:
- 优势:相比全盘扫描,1二叉树有序,1页节点load到内存之后,如果使用折半查找等算法, 可以加速内存对比效率;
2二叉树在数据无序的情况下,可以减少磁盘io次数。 - 缺点:在有序的情况下,会出现单边增长问题。
- 红黑树:
- 优势:相比二叉树,解决了数据有序情况下单边增长的问题;
- 缺点:在数据量较大的时候,无法控制树高。
我们知道,树高代表了磁盘的io次数,也是在大数量的时候,性能依然无法保障。
- b树:
- 优势:相比红黑树,b树是一种二叉平衡树,在数据量较大的情况下,解决了树高无法控制的问题。
此时的数据已经比较完美了。
但是mysql采用了更优的树结构,b+树。
- b+树:
- 优势:相比b树,1非叶子节点不存储数据,能够存储更多的数据,同时减少了磁盘io次数。
例如,innob存储引擎默认1页数据16KB,假如使用bigint数据类型,占用内存8B,磁盘地址占用内存6B,那么,1页节点就可以存储16KB / (8KB+6KB) = 1170个元素。
叶子节点如存储整行数据,1行数据1KB,那么1页节点可以存储16个元素。
那么,假如树高为3,就可以存储1170*1170*16=2000万个元素,所以,2000千万的数据遍历,只需要3次磁盘Io即可搞定。
2 叶子节点使用双向指针连接,增加了区间访问的性能。
例如,查询20<a<50,如果mysql定位到了20,就可以不再遍历索引树,而是直接根据双向指针,加载后面的节点,直到加载到数值为50的元素。
例如,查询id<20,可以定位到id为20的元素,然后使用双向指针,向前遍历即可。
索引的存储结构:
- myisam存储引擎
myisam存储引擎,为非聚簇索引结构,即索引与数据分离。
/data/tablename.frm文件,存储表结构;
/data/tablename.myi文件,存储索引,索引叶子节点,存储表数据磁盘地址。
/data/tablename.myd文件,存储表数据; - innodb存储引擎
/data/tablename.frm文件,存储表结构;
/data/tablename.ibd文件,存储主键索引树/二级索引树。
innodb为聚簇索引,主键索引树的叶子节点,存储了整行数据。
二级索引树的叶子节点,存储了主键索引树中的唯一键。
通过唯一键为主键id,如果没有主键,mysql会从第1列开始,查找没有重复元素的列来维护索引树,如果没有找到唯一键,则建立隐藏的rowid维护索引树。
所以使用二级索引树查找非索引列数据,就涉及到回表,即要根据唯一键,去主键索引树的ibd文件中找到整行数据。
为什么使用Innodb存储引擎,推荐使用整形自增类型做主键:
知道了索引树的结构,我们知道在Innodb存储引擎中,mysql默认使用主键维护主键索引树,而索引树是个有序的结构,需要对主键进行排序。
那么
- 自增有利排序。
如有的表喜欢使用uuid做主键,uuid是无序的,在排序上,对比需要消耗时间, - 自增有利索引树的维护。
在放满元素的b+树的叶子节点上插入1个元素,就需要节点分裂,树重新做平衡。
而自增的主键,插入元素,只需要在最后1个节点插入元素,或新增元素,向上提本页最小的元素上去即可。 - 整型占用空间少
相比uuid,占用的存储空间更少。
联合索引树的结构:
建立联合索引,首先对a排序,其次b排序,然后c排序,所以a有序的前提下,b才有序,b在索引树的全局并不有序,这也是最左前缀原则的由来。
但是,具体原则又有特殊处理,例如like 'a%',mysql可能会认为是常量,所以也符合最左前缀法则。
hash索引树的结构:
mysql除了可以使用b+树索引结构,还可以使用hash索引。
hash索引支持 = in ,2种查询,效率较高,可以根据col值hash,直接定位数据。但是无法支持范围匹配。