为啥没走我想要的索引

最近看报警,发现有慢日志。

现状

表结构是这样的

sql 复制代码
CREATE TABLE `A` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '名称',
  `description` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '描述',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `space_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '空间ID',
  PRIMARY KEY (`id`),
  KEY `idx_space_id` (`space_id`),
  KEY `idx_create_time` (`create_time`),
  KEY `idx_update_time` (`update_time`),
) ENGINE=InnoDB COMMENT='A表'

慢日志的语句为:

sql 复制代码
select * from `A` where space_id = ? order by create_time desc limit ?

explain查看了一下

列名 列值
type index
possible_keys idx_space_id
key idx_update_time
key_len 5
ref ``
rows ***
filtered 0.06
Extra Using where; Backward index scan

可以看到最终走的是updatetime的索引,不是spaceid,所以filtered特别低。

原因

选择索引是优化器的工作,优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。在数据库里面,扫描行数是影响执行代价的因素之一。扫描的行数越少,意味着访问磁盘数据的次数越少,消耗的 CPU 资源越少。但扫描行数并不是唯一的判断标准,优化器还会结合是否使用临时表、是否排序等因素进行综合判断。

为啥没有走spaceid索引?和sql里的order有关!

如果真的是用了spaceid,那我们来看一下会是什么流程。

explain会显示Using filesort,使用"文件排序"!

因为数据库会初始化sort_buff,查询符合spaceid的信息,将字段放入sort_buffer,然后按照create_time快速排序,按照排序结果取对应行给客户端。

sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。这样速度就更慢了。

解决方案

其实这是一个比较常规的问题,要解决的话只要创建(space_id,create_time)的联合索引即可。

有时候大家在review别人的代码的时候,也需要关注一下这点,防止线上出现这种慢查询问题。

总结

数据库方面除了会使用之外,能够知晓一些底层原理,能够避免很多问题,而且也能解决线上很多问题,推荐

  • 《MySQL技术内幕:InnoDB存储引擎》:系统讲述InnoDB,相对易懂,能帮大家建立MySQL整体认知

  • 《MySQL实战45讲》:知识点讲解清晰、深入,很多知识常用于面试、工作中

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

我的个人博客为:shidawuhen.github.io/

往期文章回顾:

  1. 设计模式

  2. 招聘

  3. 思考

  4. 存储

  5. 算法系列

  6. 读书笔记

  7. 小工具

  8. 架构

  9. 网络

  10. Go语言

相关推荐
i***132414 分钟前
Spring BOOT 启动参数
java·spring boot·后端
IT_Octopus18 分钟前
(旧)Spring Securit 实现JWT token认证(多平台登录&部分鉴权)
java·后端·spring
kk哥889924 分钟前
Spring详解
java·后端·spring
S***267526 分钟前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
码事漫谈27 分钟前
C++单元测试框架选型与实战速查手册
后端
OneLIMS33 分钟前
Windows Server 2022 + IIS + ASP.NET Core 完整可上传大文件的 报错的问题
windows·后端·asp.net
码事漫谈42 分钟前
C++ 依赖管理三剑客:vcpkg、Conan、xmake 速查手册
后端
计算机毕设匠心工作室1 小时前
【python大数据毕设实战】青少年抑郁症风险数据分析可视化系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习
后端·python
计算机毕设小月哥1 小时前
【Hadoop+Spark+python毕设】智能制造生产效能分析与可视化系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
四问四不知1 小时前
Rust语言进阶(结构体)
开发语言·后端·rust