为啥没走我想要的索引

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

现状

表结构是这样的

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语言

相关推荐
我是大猴子1 小时前
Spring代理类为何依赖注入失效?
java·后端·spring
码事漫谈1 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
码农BookSea2 小时前
ReAct:让大模型学会边想边做
后端·ai编程
码农BookSea3 小时前
10分钟掌握 JSON-RPC 协议,面试加分、设计不踩坑
后端
计算机毕设vx_bysj68693 小时前
【免费领源码】77196基于java的手机银行app管理系统的设计与实现 计算机毕业设计项目推荐上万套实战教程JAVA,node.js,C++、python、大屏数据可视化
java·mysql·智能手机·课程设计
凤年徐3 小时前
C++手撕红黑树:从0到200行,拿下STL map底层核心
c++·后端·算法
IT_陈寒3 小时前
Python的列表推导式里藏了个坑,差点让我加班到凌晨
前端·人工智能·后端
吴声子夜歌3 小时前
ES6——正则的扩展详解
前端·mysql·es6
xixingzhe23 小时前
Mysql统计空间增量
数据库·mysql
程序员萌萌3 小时前
Java之mysql实战讲解(三):聚簇索引与非聚簇索引
java·mysql·聚簇索引