索引的本质是我们记录了一个数据所在的位置,通过索引就可以很快找到所需要的数据。现实中例如书本的目录就是一种索引。
在程序的世界也有一些常见的索引模型,例如哈希表,有序数组,搜索树等。MySQL的索引用的是B+树,是一种N叉搜索树,为什么不适用其他的数据结构呢?
哈希表支持的是KV结构,根据等值查询比较好,但是如果想要范围查询,就那要查询一遍所有的数据。
有序数组支持范围查询,如果只是查看数据,那有序数组就能很好的做到,但是有序数组在增删的时候就比较麻烦,需要移动元素后面的所有数据。所以有序数组适合一些静态数据存储。
二叉搜索树如果存的数据太多,树的层数也会变多,而很多数据是存在磁盘中的,在查询数据的时候需要更多次数的访问磁盘。

innodb的索引
innodb中每个索引对应一颗B+树,根据叶子节点存储的内容分为主键索引和非主键索引。
主键索引,又叫聚簇索引,叶子节点存储的是整行数据。
非主键索引,也称为二级索引,叶子节点存的是主键的值。
根据主键查询的时候只需要扫描一颗搜索树,如果根据二级索引就需要多扫描一颗树,所以尽量使用主键查询。
但是B+树在数据不断维护过程中会有页分裂和页合并,这是会消耗性能的。为了避免频繁的叶子节点分裂,尽量使用自增主键。如果使用UUID或者别的什么字符串作为主键,在插入数据的过程中,会频繁插入到别的叶子节点中间,会使别的数据产生挪动,而使用自增主键每次插入数据都是在后面追加数据,不会触发叶子节点的分裂。
并且使用自增主键可能占用的字节数更少,整个索引占用的空间就会更小,其他的索引的叶子节点存储的是主键数据,这样其他索引占用的空间也会更小。所以从性能和存储空间两方面考虑,主键最好使用自增主键。

覆盖索引
覆盖索引发生在联合索引上,当单个字段作为非主键索引的时候,例如name有索引,但是根据name查询别的数据的时候,例如根据name查询age,还需要先在name索引树上找到主键,然后再回表,去主键索引中搜索到age数据。但如果根据name,age创建联合索引,当根据name查询age的时候,可是直接在联合索引上根据name找到age的值,不需要在回表操作,这个索引已经覆盖了我们的查询需求,索引成为覆盖索引。
覆盖索引是常用的一个性能优化手段。

最左前缀原则
也称为最左匹配原则。当联合索引有多个字段的时候,例如(name,age,weight),name字段在索引的最左边,只要查询的字段里有name字段,就会走索引,例如(name)(name,age)(name,age,weight)都会走索引,但是如果查询中没有使用左边的索引,例如(age)(age,weight)都不会走索引。
当建立联合索引的时候,要把区分度高的字段放前面,区分度低的放后面。
``五大题型,看完基本就懂!

题型一

如果sql为
SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;
如何建立索引?
如果此题回答为对(a,b,c)建立索引,那都可以回去等通知了。
此题正确答法是,(a,b,c)或者(c,b,a)或者(b,a,c)都可以,重点要的是将区分度高的字段放在前面,区分度低的字段放后面。像性别、状态这种字段区分度就很低,我们一般放后面。
例如假设区分度由大到小为b,a,c。那么我们就对(b,a,c)建立索引。在执行sql的时候,优化器会 帮我们调整where后a,b,c的顺序,让我们用上索引。

题型二

如果sql为
SELECT * FROM table WHERE a > 1 and b = 2;
如何建立索引?
如果此题回答为对(a,b)建立索引,那都可以回去等通知了。
此题正确答法是,对(b,a)建立索引。如果你建立的是(a,b)索引,那么只有a字段能用得上索引,毕竟最左匹配原则遇到范围查询就停止匹配。
如果对(b,a)建立索引那么两个字段都能用上,优化器会帮我们调整where后a,b的顺序,让我们用上索引。

题型三

如果sql为
SELECT FROM table WHERE a > 1 and b = 2 and c > 3;
如何建立索引?
此题回答也是不一定,(b,a)或者(b,c)都可以,要结合具体情况具体分析。
拓展一下
SELECT
FROM table WHERE a = 1 and b = 2 and c > 3;
怎么建索引?嗯,大家一定都懂了!

题型四

SELECT FROM table WHERE a = 1 ORDER BY b;
如何建立索引?
这还需要想?一看就是对(a,b)建索引,当a = 1的时候,b相对有序,可以避免再次排序!
那么
SELECT
FROM table WHERE a > 1 ORDER BY b;
如何建立索引?
对(a)建立索引,因为a的值是一个范围,这个范围内b值是无序的,没有必要对(a,b)建立索引。
拓展一下
SELECT * FROM table WHERE a = 1 AND b = 2 AND c > 3 ORDER BY c;
怎么建索引?

题型五

SELECT FROM table WHERE a IN (1,2,3) and b > 1;
如何建立索引?
还是对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配,所以还是(a,b)!
拓展一下
SELECT
FROM table WHERE a = 1 AND b IN (1,2,3) AND c > 3 ORDER BY c;
如何建立索引?此时c排序是用不到索引的。

索引下推
就是在联合索引中用到多个字段查询,例如联合索引(name,age), 在MySQL5.6之前,如果根据条件查询
where name = xxxx and age = 10, 会只根据name查询到主键,然后再根据主键去回表,找到对应的数据判断age是否符合。5.6之后可以在遍历索引的时候根据条件过滤掉age不等于10 的数据,这样就大大减少了回表查询的次数。