MySQL-索引
文章目录
-
Mysql中多数引擎中默认的索引结构是B+树,因此以下的规则均在索引结构是B树/B+树时才正确。
-
至于B+树的具体结构和它带来的优点请参考MySQL-索引的数据结构。
-
聚集/非聚集索引
-
聚集索引
- 聚集索引是指在索引中每个key对应的data所存储的是整行的数据。
- 在InnoDB存储引擎中,默认数据就是以主键为key构造一棵B+树,它对应的data就是整行的数据。
- 在InnoDB等引擎中每张表只有一个聚集索引。
-
非聚集索引
- 非聚集索引在索引中每个key对应的data只存储了索引键中的所有键值和主键ID。
- 除主键默认生成的聚集索引外,我们创造的其他索引均为非聚集索引。
- 在通过非聚集索引查找数据时:
- (1)在通过非聚集索引查找数据时,先在非聚集索引中查找到此key,并在key对应的data中找到其所在行的主键id
- (2)之后回表在聚集索引中利用主键id来查找对应的行的所有数据。(若此索引中包含了所有要查的属性则无需回表)因此使用非聚集索引时会进行两次索引查询。
-
聚集-非聚集索引的对比
- 聚集索引包含了整行的数据,因此不需要回表查询。非聚集索引只包含索引列的数据和主键id,因此当查询的属性不包含在其内的话需要回表再查询一次聚集索引。
- 因此当创建索引时,如果想避免回表,则利用索引属性和需要查的其他属性一起创建联合索引,此时将可以避免回表。
-
-
联合索引
-
有时一条SQL需要进行多个判断或排序,这时单个索引的优化已经无法满足优化需要。
-
联合索引是用多个属性来建造索引,属性之间具有顺序。
- 例如:
select * from table where c=1 and b=1 and a=1;
- 此时我们应建立(c,b,a)这个顺序的联合索引。
- 例如:
-
最左匹配原则
- 联合索引是按照属性的顺序来建立索引的。因此只有最左侧的所有属性都使用了的情况下才可以对使对此属性的查询继续走联合索引。
- 例如建立了(a,b,c)顺序的联合索引
select * from table where a=1 and b=1;
- 因为a为联合索引第一个属性所以它可以走索引,而b左侧的a已经走了联合索引,所以b也可以走索引。
select * from table where a=1 and c=1;
(部分使用)- 因为a为联合索引第一个属性所以它可以走索引,而c左侧的b没有走联合索引,所以c不可以走索引。
select * from table where b=1 and c=1;
(完全不可使用)- 因为b左侧的a没有走联合索引,所以它不可以走索引,所以b右侧的c也因为b没有走索引而不能走索引。
- 例如建立了(a,b,c)顺序的联合索引
- 联合索引是按照属性的顺序来建立索引的。因此只有最左侧的所有属性都使用了的情况下才可以对使对此属性的查询继续走联合索引。
-
避免回表
- 联合索引中存储的有联合索引中使用的所有属性和主键id,因此如果查询中需要得到的属性都在联合索引中,则无需回表去查主键的聚集索引。
-
-
索引的用途
-
(1)数据检索
- 在一个表中利用where语句进行数据检索时,为where判断条件中的属性添加索引可以加快查询速度。
- 例:
select * from table where a = 90000;
- 此时为属性a添加索引,可以加快查询速度。
- 例:
- 在一个表中利用where语句进行数据检索时,为where判断条件中的属性添加索引可以加快查询速度。
-
(2)聚合函数
- 在一个SQL中需要利用聚合函数时,为聚合函数中的属性添加索引可以加快查询速度。
- 包括:min(),max(),count(*)
- 例如:
select max(d) from table;
- 此时为属性d添加索引,可以加快查询速度,在B+树中寻找最大值无需全表扫描。
- count(*)为统计行数,因为主键的聚集索引中包含整行数据,一个页所存放的行数有限,因此优先使用我们创建的非聚集索引,这样一个页中的行数很多,IO减小。
- 在一个SQL中需要利用聚合函数时,为聚合函数中的属性添加索引可以加快查询速度。
-
(3)排序
- 在一个SQL中需要按照一个或多个属性的顺序来返回排序后的查询结果。
- 例如:
select * from table order by a;
- 此时为属性a添加索引,可以加快速度,因为B+树中的数据是有序,在索引中查询省略了排序的步骤。
- 如果是按照两个属性来排序,则按照顺序建立这两个属性的联合索引。
- 如果是先等值查询在排序,则按照等值查询属性和排序属性的顺序来创建联合索引。
- 例如:
- 在一个SQL中需要按照一个或多个属性的顺序来返回排序后的查询结果。
-
(4)避免回表
- 在一个SQL中需要按照一个属性来筛选数据,并返回整行的数据。
- 例如:
select a,b from t9_1 where a=90000;
- 因为我们创造的非聚集索引中只会存储索引属性和主键id,不会存储其他属性,因此如果对这条语句我们若只建立以a为key的索引则在此索引中查到主键id后还需要到聚集索引中查询b属性的值。
- 因此我们应该创建以a,b为key的联合索引。来避免回表
- 例如:
- 在一个SQL中需要按照一个属性来筛选数据,并返回整行的数据。
-
(5)关联查询
- 在SQL中用到了关联查询,则为关联的两个表的关联字段均添加索引。
- 例如:
select * from table1 left join table2 on table1.a=table2.a
- 则我们应该为table1的a属性和table2的b属性均添加索引,可以加快查询速度。
- 例如:
- 在SQL中用到了关联查询,则为关联的两个表的关联字段均添加索引。
-
-
普通索引和唯一索引
-
我们知道普通索引的字段可以写入相同的值,而唯一索引的字段不可以写入相同的值。
-
Insert Buffer/Change Buffer
- Insert Buffer是最初为了减小磁盘读取和将多次插入合并为一次操作而引入的,只针对insert命令,后来又引入了Change Buffer可以将delete,update操作均进行合并。
- 对于这些命令先判断索引页是否在缓冲池中,在则直接插入,不在则放入change buffer中,然后按照一定频率和情况进行buffer和辅助索引页子节点的合并操作。
- 这样可以将多个操作合并在一次操作中,提升了性能。
- 但insert/change buffer只对辅助索引且必须为非唯一索引生效。
- 唯一索引必须将数据页读入内存进行唯一性约束判断,因此不能使用buffer来合并多个操作。
-
普通索引和唯一索引的区别
- (1)数据修改时,普通索引可以使用Change Buffer,唯一索引不能。
- (2)数据修改时,在RR隔离级别中,唯一索引因为要判断唯一性,因此更容易出现死锁。
- (3)查询数据时,唯一索引查到第一条即可返回,普通索引需要将所有的匹配节点均判断一次。
-
-
索引的缺点
- 索引占用物理空间。
- 更新数据时,索引也需要更新。
- 因此建立索引时应该针具体情况来分析是否需要。