Mysql联合索引是怎么存储的
联合索引
联合索引是将多列作为索引字段建立B+树。但是实际上MySQL只会为一个联合索引建立一个B+树。如使用C2和C3作为联合索引,规则如下:
- 先把各个记录和页按照c2列进行排序。
- 在记录的c2列相同的情况下,采用c3列进行排序
每条目录项记录都由c2、c3、页号这三个部分组成,各条记录先按照c2列的值进行排序,如果记录的c2列相同,则按照c3列的值进行排序。
最左前缀原则
在平时开发中,最常见的是单列索引(比如主键primary id),但是在需要多条件查询的时候,也会创建联合索引。单列索引也可以看成特殊的联合索引。比如在user表中,给name和phone建立一个联合索引。
ALTER TABLE user_innodb add INDEX comidx_name_phone(name,phone); -- 创建联合索引
下图是B+树的索引结构,是一个单值索引:
可以看出,所有非叶子节点的构成都是由两部分组成,索引值+指针,而单值索引说的就是在索引值这里只有一个值(比如id),而联合索引在索引值可能会有多个值(比如name和phone)
与单值索引的不同
- 联合索引在B+树中是复合的数据结构
- 由于B+树本身是有序的,所以联合索引是从左到右的顺序来建立搜索树的(name在左边,phone在右边)。从上图可以看出,name是有序的,phone是无序的。当name相等时,phone才是有序的。
- 当存储引擎是innoDB时,叶子节点存储的是数据/主键
Q1:联合索引如何查找数据?
比如,使用where name = ‘zhangsan’ and phone='1320xx’去查询数据的时候
- B+树会优先比较name来确定下一步应该搜索的方向,往左还是往右
如果name相同的时候就比较phone - 但是如果查询条件没有name,就不知道第一步应该查询哪个节点,因为建立搜索树的时候name是第一个比较因子,所以用不到索引。
Q2:联合索引与单值索引的关系?
假设项目里有两个查询很慢:
SELECT * FROM user_innodb WHERE name= ?;
SELECT * FROM user_innodb WHERE name= ? AND phone=?;
按照我们的想法,一个查询创建一个索引,所以针对这两条SQL创建两个索引,这种做法觉得正确吗?
CREATE INDEX idx_name on user_innodb(name);
CREATE INDEX idx_name_phoneonuser_innodb(name,phone);
当我们创建一个联索引的时候,用左边的字段name去查询的时候,也能用到索引,所以单独为name创建一个索引完全没必要,相当于建立了两个联合索引(name),(name,phone)
如果创建三个字段的索引index(a,b,c)相当于创建三个索引:index(a),index(a,b),index(a,b,c)。用where b=?和where b=? and c=? 和where a = ? and c = ?是不能使用到索引。以为不能不用第一个字段,也不能中断。
因为联合索引中包含了多个字段,所以不能像单值索引那样直接使用,需要遵守规则?
就是最左前缀原则:带头大哥不能死,中间兄弟不能断
1.建立索引时,一定要把常用的列放在最左边。比如下面三个语句,能用到联合索引吗?
使用两个字段,可以用到联合索引(注:两个字段的顺序颠倒并不影响,因为全值匹配时mysql会优化字段顺序)
EXPLAIN SELECT * FROM user_innodb WHERE name= '张三' AND phone='12345678910'
2.使用左边的name字段,可以用到联合索引:
EXPLAIN SELECT * FROM user_innodb WHERE name= '张三'
3.使用右边的phone字段,无法使用索引,全表扫描:
EXPLAIN SELECT * FROM user_innodb WHERE phone= '12345678910'
不要在索引上做任何操作,因为可能会导致索引失效,转而全表扫描
参考原文链接:https://blog.csdn.net/qq_38487209/article/details/125111125