索引
索引是为了加速对表中数据行进行检索而创建的一种分散存储的数据结构。
# 类型
# Hash索引
索引只存储对应的hash值和行指针
- 缺点
- 不支持覆盖索引
- 不支持范围比较
- 不支持部分索引
- hash冲突时需要遍历所有相关行进行比对,冲突代价比较高
- 优点
- 节省空间,比如对url建立索引
InnoDB引擎有一个特殊功能叫自适应哈希索引,当InnoDB注意到某些索引值被使用的非常频繁时,它会在内存中基于B-Tree索引之上再建立一个哈希索引。这是一个自动的内部行为,用户无法控制或配置,不过如有必要,可以关闭该功能:--innodb-adaptive-hash-index[={OFF|ON}]
在繁重的工作负载(例如多个并发联接)下,对自适应哈希索引的访问有时会成为争用的根源。使用 LIKE 运算符和 % 通配符的查询也往往不会受益。
# B Tree
多叉平衡树。每个节点可以存储多个关键字和对应的指针。每个节点的子节点数量为关键字数量+1,这样可以大大降低树的高度,从而减少磁盘IO次数。利用操作系统每次读取磁盘的一块区域到内存的性质,可以将每个节点大小刚好控制为一次磁盘读取的大小,即页大小16k。
但是在做范围查找的时候,由于非叶子节点保存有数据,会导致回溯非叶子节点,增加IO次数。
# B+ Tree
针对B树做的优化,非叶子节点不保存数据,只保存关键字和指针,这样可以使得每个节点存储更多的关键字,从而更大程度降低树的高度,减少磁盘IO次数。叶子节点使用链表连接,可以使得范围查找更加高效。
# 聚簇索引与非聚簇索引
聚簇索引:索引每个叶子节点存储主键、事务id、回滚指针、其他字段等。InnoDB的主键索引就是聚簇索引。 非聚簇索引:索引中叶子节点存放的是主键值,通过主键值再去聚簇索引中查找其他字段。
# 使用
当需要对过长的字符字段建立索引时,可以考虑前缀索引,即取字段前n个字符作为索引,而不是整个字段。 eg. ALTER TABLE user ADD KEY (name(5)); 前缀索引无法做ORDER BY 和GROUP BY ,也无法做覆盖扫描
将OR 改写成UNION
使用覆盖索引,即索引中的字段包含了要查询字段,所以应避免使用select *,避免回表
使用索引来做排序。在覆盖索引的基础上,使索引的列顺序与order by子句的顺序完全一致,并且列的排序方向(倒序或正序)都一样时,MySQL会使用索引来对结果进行排序。
大表数据导入到其它数据库时,需在新数据库上先关闭索引,然后再添上索引,要不然效率就太低了。
修改数据通过索引条件可以只锁部分行,如果不走索引会对表中所有数据行加行锁。
# 索引失效
- 在索引上使用!=或<>
- 使用or连接索引
- 对于多列的索引,不按照顺序使用
- 如果索引类型是字符串,不加引号会使得索引失效
- like模糊匹配以%开始
- 在索引字段上使用运算或函数
- 索引值较少,比如枚举,或者离散度不高
# SQL命中索引,但任然耗时
如果SQL命中索引,但是依旧比较耗时,可以从以下几个方面进行分析和处理:
# 索引是否覆盖查询
如果SQL语句中使用了SELECT * 或者 SELECT 字段列表,而索引中并没有包含所有查询的字段,那么即使命中索引,也需要回表查询数据,会增加查询的耗时。可以通过优化SQL语句,只查询需要的字段,或者使用覆盖索引来避免回表查询。
# 索引是否合理
索引的设计是否合理,是否能够满足查询的需求。可以通过查看索引的使用情况,分析索引的命中率和效率,来判断是否需要调整索引的设计。
例如使索引的列顺序与order by子句的顺序完全一致,避免再次排序。
# 数据量是否过大
如果数据量过大,即使命中索引,也需要进行大量的磁盘I/O操作,会增加查询的耗时。可以通过优化SQL语句,减少查询的数据量,或者使用分页查询等方式来避免一次性查询大量数据。
# 硬件资源是否充足
如果硬件资源不足,比如CPU、内存、磁盘等,会影响查询的效率。可以通过增加硬件资源,或者优化数据库的配置参数来提高查询的效率。
# 是否存在锁等并发问题
如果存在锁等并发问题,会导致查询的等待时间增加,从而影响查询的效率。可以通过优化SQL语句,减少锁的竞争,或者调整数据库的并发控制参数来避免并发问题。