一、什么是索引?
索引其实就是帮助Mysql高效获取数据的排好序的数据结构。能够在大量数据中快速定位我们想要的数据。
二、索引有哪些?
2.1 单列索引
单列索引指的是一个列组成的索引。
单列索引包含:
1.普通索引:值可以为空和重复,就是为了加快查询
2.唯一索引:值不能重复、为空
3.主键索引:和唯一索引类似,一般用于标识业务的唯一序号
2.2二级索引(联合索引)
二级索引是多个列组合构建成的,如果不是联合主键索引,那么索引value存放的就是主键id,否则就是对应的数据,使用时要符合最左前缀法则。
三、索引的数据结构是什么?
Mysql最终选择B+树作为索引的数据结构。
1.为什么不选择使用二叉树?
因为二叉树对于单列自增的数据而言,产生的结果类似链表,如果要查询的数据在链表的末尾,那么查询仍然需要遍历整个链表。
2.为什么不使用红黑树?
因为红黑树的树的高度不能确定,如果在大量的数据为前提下,树的高度能达到一个极为恐怖的程度,查询元素实际上就是遍历树的高度,对查询数据的效率没有任何提升。
3.为什么不使用B树?
因为B树的每一个节点都存放数据,那么一页能存放的索引元素就非常少,会导致树的高度没办法控制在2、3层内。B树的叶子节点之间没有用指针进行关联,对于区间查询没有提供很好的支持。
选择使用B+树是因为只有B+树的非叶子节点只存放冗余的索引,只有叶子节点才会存放完整的数据,同时叶子节点之间使用指针进行关联,利于区间查询,并且节点之间是排好序的。
四、索引的优化
1.分页查询优化
select * from test_table limit 10000,10;
对于上面这条sql,实际的查询仍然是要先查询出前面的10000条数据,然后抛弃掉,再获取后面的10条数据,这对于数据量较大的场景而言,效率是非常低下的。
1.1 使用主键id进行优化分页查询
对于自增且连续的主键id,我们可以将sql改写成如下形式:
select * from test_table where id >10000 limit 10;
这样就会利用主键索引进行过滤数据,实际上也就取10条数据,对比上面的sql,性能提升时显著的。但是使用这种需要满足两点:1.主键自增且连续; 2.主键是排好序的。
1.2 根据字段进行优化分页查询
select * from test_table e inner join (
select id from test_table order by name limit 90000,5
) ed on e.id = ed.id;
这样核心思路就是尽量让排序的语句返回字段减少,然后根据返回的索引字段,再通过索引树进行过滤,提高查询速度。
2.关于Join关联查询优化
对于Join关联表的优化,核心只有两条建议:
1.关联的字段要用索引,这样在查询的时候可以走索引,减少查询损耗的时间
2.要使用小表驱动大表,这样做的好处是避免大表的数据频繁过滤,导致浪费没必要的数据过滤
3.in和exists优化
in:当B表的数据集小于A表时,in优先exists
select * from test_table where id in (
select id from testB
)
-- 等价于
-- select id from testB B;
-- select * from test_table A where A.id = B.id;
exists:当A表的数据小于B表时,exists优先于in。将A表的数据跟B表的数据进行对比,再决定是否要存留A表的数据。
select * from test_table A where exists (
select id from testB B where A.id = B.id
)
-- 等价于
-- select * from test_table A
-- select id from testB B where A.id = B.id
五、索引设计原则
其实索引的设计不应该这么早,而是应当以业务主体的sql开发完后,进行过初轮测试后,再将设计到相关表的sql统一取出,再根据这些sql进行设计索引。
1.代码先上,索引后上——这样做可以更加针对性的对索引进行设计,设计索引时也更加的有针对性。
2.同一个表尽量设计两三个联合索引,并将这些联合索引覆盖条件——这样做可以满足80%业务的查询需求,对于剩下20%的特殊需求,可以单独建立单个索引进行处理。
3.不要在小基数字段上建立索引——索引的查询始终要回归到索引树上,如果建立在小基数上,对于索引过滤数据而言,是没有优化作用的,二分查找也并没有提高任何查询效率。
4.针对慢sql,可以通过后台监控、开启慢查询等获取,然后再针对性的对这些sql建立索引或拆分sql。
5.索引不宜建多——索引是使用B+树进行维护,B+树也有自平衡,过多的索引树,Mysql维护起来是要消耗不少性能,对于数据量巨大的表而言,更是如此。