MySQL为什么命中索引还会全表扫描?简述覆盖索引和回表

什么是索引?

索引其实是一种能高效帮助MYSQL获取数据的数据结构,通常保存在磁盘文件中,好比一本书的目录,能加快数据库的查询速度。除此之外,索引是有序的,所以也能提高数据的排序效率。

通常MYSQL的索引包括聚簇索引覆盖索引复合索引唯一索引普通索引,通常底层是B+树的数据结构。

总结一下,索引的优势在于:

  • 提高查询效率。

  • 降低数据排序的成本。

缺点在于:

  • 索引会占用磁盘空间。

  • 索引会降低更新表的效率。因为在更新数据时,要额外维护索引文件。

索引的类型

  • 聚簇索引

索引列的值必须是唯一的,并且不能为空,一个表只能有一个聚簇索引。

  • 唯一索引

索引列的值是唯一的,值可以为空。

  • 普通索引

没有什么限制,允许在定义索引的列中插入重复值和空值。

  • 复合索引

也叫组合索引,用户可以在多个列上组合建立索引,遵循“最左匹配原则”,在条件允许的情况下使用复合索引可以替代多个单列索引的使用。

聚簇索引

  • 如果表设置了主键,则主键就是聚簇索引
  • 如果表没有主键,则会默认第一个NOT NULL,且唯一(UNIQUE)的列作为聚簇索引
  • 以上都没有,则会默认创建一个隐藏的row_id作为聚簇索引

InnoDB的聚簇索引的叶子节点存储的是行记录(其实是页结构,一个页包含多行数据),InnoDB必须要有至少一个聚簇索引。

由此可见,使用聚簇索引查询会很快,因为可以直接定位到行记录。

普通索引

普通索引也叫二级索引,笼统的讲,除聚簇索引外的索引,即非聚簇索引。InnoDB的普通索引叶子节点存储的是主键(聚簇索引)的值,而MyISAM的普通索引存储的是记录指针。

示例

id 字段是聚簇索引,age 字段是普通索引(二级索引)

select * from user;

+----+--------+------+
| id | name  | age |
+----+--------+------+
| 1 | 张三  |  30 |
| 2 | 李四  |  20 |
| 3 | 王五  |  40 |
| 4 | 刘八  |  10 |
+----+--------+------+

索引存储结构

id 是主键,所以是聚簇索引,其叶子节点存储的是对应行记录的数据
在这里插入图片描述

普通索引(secondaryIndex)

age 是普通索引(二级索引),非聚簇索引,其叶子节点存储的是聚簇索引的的值

在这里插入图片描述
聚簇索引(ClusteredIndex)

如果查询条件为主键(聚簇索引),则只需扫描一次B+树即可通过聚簇索引定位到要查找的行记录数据。如:select * from user where id = 1;
在这里插入图片描述

索引查找过程

如果查询条件为普通索引(非聚簇索引),需要扫描两次B+树,第一次扫描通过普通索引定位到聚簇索引的值,然后第二次扫描通过聚簇索引的值定位到要查找的行记录数据。

如:select * from user where age = 30;

  1. 先通过普通索引 age=30 定位到主键值 id=1
  2. 再通过聚集索引 id=1 定位到行记录数据

普通索引查找过程第一步
在这里插入图片描述
普通索引查找过程第二步
在这里插入图片描述

回表查询

先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据,需要扫描两次索引B+树,它的性能较扫一遍索引树更低。

索引覆盖

只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。例如:select id,age from user where age = 10;

如何实现覆盖索引

常见的方法是:将被查询的字段,建立到联合索引里去

1、实现:select id,age from user where age = 10;

explain分析:因为age是普通索引,使用到了age索引,通过一次扫描B+树即可查询到相应的结果,这样就实现了覆盖索引
在这里插入图片描述

2、实现:select id,age,name from user where age = 10;

explain分析:age是普通索引,但name列不在索引树上,所以通过age索引在查询到id和age的值后,需要进行回表再查询name的值。此时的Extra列的NULL表示进行了回表查询
在这里插入图片描述
为了实现索引覆盖,需要建组合索引idx_age_name(age,name)

drop index idx_age on user;
create index idx_age_name on user(`age`,`name`);

explain分析:此时字段age和name是组合索引idx_age_name,查询的字段id、age、name的值刚刚都在索引树上,只需扫描一次组合索引B+树即可,这就是实现了索引覆盖,此时的Extra字段为Using index表示使用了索引覆盖。

  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在使用索引时,有几个注意事项需要注意: 1. 索引选择:选择适当的列作为索引,通常是那些经常用于过滤、排序和连接的列。避免在大文本字段或者频繁更新的字段上创建索引,因为这可能会导致索引变得庞大,影响性能。 2. 索引覆盖:尽量设计覆盖索引,即索引包含了查询所需的所有列,这样可以避免回表操作,提高查询性能。 3. 多列索引:对于经常一起使用的多个列,在它们上创建多列索引可以提高查询性能。但要注意不要创建过多的索引,因为它们会占用额外的存储空间,并且在更新数据时会增加开销。 4. 统计信息:MySQL使用统计信息来优化查询执行计划。确保及时更新统计信息,以便优化查询性能。可以使用ANALYZE TABLE命令手动更新统计信息。 5. 索引失效:有些查询条件可能会导致索引失效,这时数据库可能会选择全表扫描。常见的情况包括在索引列上进行函数操作、模糊查询中使用通配符开头、使用OR连接多个条件等。在这些情况下,需要仔细评估查询条件,并根据需要对表结构或查询语句进行优化。 总的来说,使用索引可以显著提高查询性能,但在创建索引时需要注意选择合适的列、设计覆盖索引、避免创建过多的索引,并及时更新统计信息。此外,需要留意查询条件可能导致索引失效的情况,做好优化工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值