MySQL 如何优化慢查询?

2023-11-01

一、前言

在日常开发中,我们往往会给表加各种索引,来提高 MySQL 的检索效率。
但我们有时会遇到明明给字段加了索引,并没有走索引的Case。 进而导致 MySQL 产生慢查询。
严重场景下,甚至出现主从延迟、数据库拖垮的极端事故。

本文梳理出索引失效的几种常见场景给大家参考。

二、技术基础

Explain 命令使用

只要我们在 SQL 前加上 explain,就可以分析出,当前环境下 MySQL 的“查询方式”以及“索引选择”。

首先大致看下每个字段的含义:

列名 含义
id 每个select操作的唯一标识
select_type 查询的类型,我们可以根据该字段判断查询的性质,包括查询是简单/复杂查询类型
table 查询访问表的别名
type 关联的类型,mysql把查询过程都视为关联,不管是单表/多表。这个字段也是衡量查询性能的关键字段之一
possible_keys 查询可能会使用哪些索引,这列是基于查询访问的列来判断的
key mysql最终决定使用哪个索引(这个索引不一定出现在possible_keys中)
key_len mysql在索引里使用的字节数,我们可以根据它推断具体使用了索引中的哪些字段
ref 查找所用的列/常量
rows mysql估算的预计扫描行数,这个数字和实际扫描的行数可能相差甚远,包括limit语句对于这个估算值也是不起作用的
filtered 表里符合条件的记录数的百分比的估计,我们可以用这个字段大致估计表关联时关联的记录数
extra 包含一些额外信息,也是我们优化时需要重点关注的字段

Type(重点看)

type 列表示了 MySQL 关联的类型,它代表了mysql是如何在表里找数据的。

下面按性能从高到低的顺序介绍type类型: 以下四种类型,说明 “性能很好,一般无需优化”

  • system:表里就一条数据
  • const:一般是针对主键/唯一键的等值查询,mysql可以把这类查询优化为一个常量表达式
  • eq_ref:一般出现在多表join时,针对主键/唯一键的等值查询,mysql知道只需要返回一条记录
  • ref:多表 join 时,针对索引字段的查询

以下几种类型,需要 “看具体情况,决定是否要优化”

  • fulltext:关联使用了全文索引
  • ref_or_null:查询走了索引,但是除此之外还要判断字段是不是null,如果出现这种类型,可以考虑这个字段是否有为空的必要
  • index_merge:使用了索引合并优化,如果高频出现,可以考虑是不是索引设计有问题。
  • unique_subquery:in 子句中的子查询,如果只访问主键/唯一键可能会出现这种 type,并不常见
  • index_subquery:同样是 in 里的子查询,访问了索引列,并不常见
  • range:对索引字段的范围扫描,一般出现在带有比较的查询语句中,一些in和or的查询也会导致这种类型的扫描

以下两种类型,需要 “优化 & 避免出现”

  • index:按索引进行全表扫描,如果查询不是覆盖索引的,可能会产生很大量的随机IO
  • all:全表扫描

三、准备工作

  1. 建一张 user
CREATE TABLE `user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` bigint(20) NOT NULL COMMENT '用户uuid',
  `user_name` varchar(64) DEFAULT '' COMMENT '用户昵称',
  `email` varchar(64) DEFAULT '' COMMENT '邮箱',
  `age` tinyint(4) DEFAULT '1' COMMENT '年龄',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_userid` (`user_id`),
  KEY `idx_username_email_age` (`user_name`,`email`,`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
复制代码
  1. 初始化一些数据
-- 创建存储过程
delimiter $

CREATE PROCEDURE insert_user(IN limit_num int)
BEGIN
 DECLARE i INT DEFAULT 10;
    DECLARE user_id bigint(20) ;
    DECLARE username varchar(64) ;
    DECLARE email varchar(64) ;    
    DECLARE age TINYINT(4) DEFAULT 1;
    WHILE i < limit_num DO
        SET user_id =  FLOOR(RAND() * 100000000);
        SET username = CONCAT("647-",i);
        SET email = CONCAT(username,"@163.com");
        SET age = FLOOR(RAND() * 100);
        INSERT INTO `user` VALUES (NULL, user_id, username, email, age, NOW(), NOW());
        SET i = i + 1;
    END WHILE;

END $
-- 调用存储过程
call insert_user(100);
复制代码

四、几种常见的索引失效场景

1. 联合索引不满足最左匹配原则

  • 错误示例:
explain select * from user where age = 20 and email = "647@163.com";
复制代码
  • 分析结果:

  • 优化思路:

根据业务场景,合理的建立相应的联合索引。

2. 范围查询,数量级过大,默认走全表扫描

一般来说,MySQL 判断数量级返回超过全数的 10% ~ 30%(或者达到某个阈值),默认会走全表扫描。

  • 错误示例:
explain select * from user where user_id > 10;
复制代码
  • 分析结果:

  • 产生原因:MySQL 优化器判断走索引&回表带来的消耗,比走全表还要多。因此,会走全表扫描。

  • 优化思路:

根据业务场景,预估返回数量级。如果数量级过大,可以分批拉取。
反之,可以加 limit 或者 force index 走索引。

3. 索引列参与运算

  • 错误示例:
explain select * from user where id + 1 = 2;
复制代码
  • 分析结果:

  • 优化思路:

不要用数据库做运算,不浪费宝贵的数据库资源。

4. 索引列使用了函数

  • 错误示例:
explain select * from user where SUBSTR(user_id,1,3) = '100';
复制代码
  • 分析结果:

  • 优化思路:

不要用数据库做函数运算,不浪费宝贵的数据库资源。

5. 错误的 like 使用

  • 错误示例:
explain select * from user where user_name like '%00%';
复制代码
  • 分析结果:

  • 优化思路:

严禁使用左%匹配,要用只能用右%匹配。
如果实在有业务场景,可以使用 ES 做。

6. 隐式类型转换

  • 错误示例:
explain select * from user where user_name = 647;
复制代码
  • 分析结果:

user_namevarchar 类型,传入 INT 比较,会产生 INT -> varchar 的隐式类型转换导致索引失效。

  • 特殊 Case:
explain select * from user where user_id = "647";
复制代码
  • 分析结果:

user_idbigint 类型,如果传入字符串比较。虽然产生隐式转换,但不会导致索引失效。

  • 优化思路:

注意字段类型,避免隐式转换。

7. OR 使用不当

  • 错误示例:
explain select * from user where user_name = "647" or email = "647@163.com";
复制代码
  • 分析结果:

  • 优化思路:

确保 or 的两边都要有索引。

8. 两个索引列做比较

  • 错误示例:
explain select * from user where user_id > id;
复制代码
  • 分析结果:

  • 优化思路:

不要对两个列做比较。

9. 非主键列,加上 not,索引失效

in 会走索引,not in 不会走索引 exists 会走索引,not exists 不会走索引 is null 会走索引,is not null 不会走索引

  • 错误示例:
explain select * from user where user_id not in (647)
复制代码
  • 分析结果:

  • 优化思路:

不要用 not。

10. 非主键列,order by 可能导致索引失效

具体是否失效,和使用的 MySQL 版本也有一定关系。 具体需要根据 explain 分析。

如果 MySQL 版本支持,需要注意满足“最左原则”。

  • 错误示例:
explain select * from user order by user_id;
复制代码
  • 分析结果:

  • 优化思路:

非主键列,尽量不要用 order by。实在要用,需要先用 explain 分析是否可以走索引。
如果条件允许,可以用 ES 代替。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL 如何优化慢查询? 的相关文章

  • 使用 LinkedList 实现下一个和上一个按钮

    这可能是一个愚蠢的问题 但我很难思考清楚 我编写了一个使用 LinkedList 来移动加载的 MIDI 乐器的方法 我想制作一个下一个和一个上一个按钮 以便每次单击该按钮时都会遍历 LinkedList 如果我硬编码itr next or
  • 学说迁移后备

    我们正在使用原则迁移 当迁移包含多个操作并且其中一个操作失败时 通常会出现问题 例如 如果迁移添加了 5 个外键 其中第 5 个失败 而字段长度不同 则修复字段错误并重新生成迁移不会not修复整个问题 而现在出现一个与 4 个密钥已存在有关
  • Spring AspectJ 在双代理接口时失败:无法生成类的 CGLIB 子类

    我正在使用Spring的
  • 如何在 Spring 中禁用使用 @Component 注释创建 bean?

    我的项目中有一些用于重构逻辑的通用接口 它看起来大约是这样的 public interface RefactorAwareEntryPoint default boolean doRefactor if EventLogService wa
  • Java 集合的并集或交集

    建立并集或交集的最简单方法是什么Set在 Java 中 我见过这个简单问题的一些奇怪的解决方案 例如手动迭代这两个集合 最简单的单行解决方案是这样的 set1 addAll set2 Union set1 retainAll set2 In
  • MySQL 追加字符串

    How can I append a string to the end of an existing table value Let s say I have the table below And let s say that Mari
  • 没有 Spring 的自定义 Prometheus 指标

    我需要为 Web 应用程序提供自定义指标 问题是我不能使用 Spring 但我必须使用 jax rs 端点 要求非常简单 想象一下 您有一个包含键值对的映射 其中键是指标名称 值是一个简单的整数 它是一个计数器 代码会是这样的 public
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • 如何在用户输入数据后重新运行java代码

    嘿 我有一个基本的java 应用程序 显示人们是成年人还是青少年等 我从java开始 在用户输入年龄和字符串后我找不到如何制作它它们被归类为 我希望它重新运行整个过程 以便其他人可以尝试 的节目 我一直在考虑做一个循环 但这对我来说没有用
  • Spring Boot Data JPA 从存储过程接收多个输出参数

    我尝试通过 Spring Boot Data JPA v2 2 6 调用具有多个输出参数的存储过程 但收到错误 DEBUG http nio 8080 exec 1 org hibernate engine jdbc spi SqlStat
  • 尝试将 Web 服务部署到 TomEE 时出现“找不到...的 appInfo”

    我有一个非常简单的项目 用于培训目的 它是一个 RESTful Web 服务 我使用 js css 和 html 创建了一个客户端 我正在尝试将该服务部署到 TomEE 这是我尝试部署时遇到的错误 我在这里做错了什么 刚刚遇到这个问题 我曾
  • java for windows 中的文件图标叠加

    我正在尝试像 Tortoise SVN 或 Dropbox 一样在文件和文件夹上实现图标叠加 我在网上查了很多资料 但没有找到Java的解决方案 Can anyone help me with this 很抱歉确认您的担忧 但这无法在 Ja
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • 如何将双精度/浮点四舍五入为二进制精度?

    我正在编写对浮点数执行计算的代码的测试 不出所料 结果很少是准确的 我想在计算结果和预期结果之间设置一个容差 我已经证实 在实践中 使用双精度 在对最后两位有效小数进行四舍五入后 结果始终是正确的 但是usually四舍五入最后一位小数后
  • 使用 svn 1.8.x、subclise 1.10 的 m2e-subclipse 连接器在哪里?

    我读到 m2e 的生产商已经停止生产 svn 1 7 以外的任何版本的 m2e 连接器 Tigris 显然已经填补了维护 m2e subclipse 连接器的空缺 Q1 我的问题是 使用 svn 1 8 x 的 eclipse 更新 url
  • 双枢轴快速排序和快速排序有什么区别?

    我以前从未见过双枢轴快速排序 是快速排序的升级版吗 双枢轴快速排序和快速排序有什么区别 我在 Java 文档中找到了这个 排序算法是双枢轴快速排序 作者 弗拉基米尔 雅罗斯拉夫斯基 乔恩 本特利和约书亚 布洛赫 这个算法 在许多数据集上提供

随机推荐

  • Qt5 Qstring::asprintf(“%.3f“, a)精度问题,有时四舍五入,有时直接丢弃。

    问题描述 提示 这里描述具体问题 在Qt5 12开发软件时发现 用Qstring asprintf 3f a 这个函数做精度控制 有时直接四舍五入 有时直接将精度后面的数据拿掉 例如 Qstring asprintf 3f a 四舍五入 f
  • 机器学习算法 决策树

    文章目录 一 决策树的原理 二 决策树的构建 2 1 ID3算法构建决策树 2 2 C4 5 算法树的构建 2 3 CART 树的创建 三 决策树的优缺点 一 决策树的原理 决策树 Decision Tree 是一种非参数的有监督学习方法
  • 10.12黄金原油资讯直通车,黄金原油区间震荡后市操作建议

    黄金消息面与技术面解析 消息面 本周显然又是一个 超级周 数据方面 将迎来中国CPI PPI数据和进出口数据 美国将公布CPI PPI 零售销售等重磅经济数据 风险事件方面 OPEC EIA和IEA都将公布原油市场月度报告 美联储多位票委和
  • eslint+prettier+vue3格式化

    项目里面安装并配置eslint 参考官网执行如下命令 npm init eslint config 等价于 npm install eslint D 安装eslint npx eslint init 初始化配置eslint 执行后会有一些配
  • 【论文笔记】:UnitBox

    Title 2016 ACM MM UnitBox An Advanced Object Detection Network Abstract 传统的目标框含有四个独立的坐标变量 丢失了相互之间的信息 导致AP下降 Unit Box 提出了
  • java操作RabbitMQ

    1 创建虚拟主机 交换机 队列 RabbitMQ提供了自己的管理界面 可以通过管理界面来完成VirtualHost Exchange queue的创建 1 1创建VirtualHost 1 2创建交换机 创建交换机的时候需要指定虚拟主机以及
  • 切换默认python版本(解决ROS中python默认版本为python2的问题)

    1 前言 许多小伙伴在安装完ROS以后 需要基于python3写ROS程序 尤其是部署深度学习算法 但是ROS默认的python版本为python2 导致无法兼容一些基于python3写的算法 有的小伙伴会选择利用anaconda来创建py
  • 蓝桥杯单片机之AT24C02模块的使用

    蓝桥杯单片机之AT24C02时钟模块的使用 简介部分 EEPROM AT24C02 引脚示意 设备地址 Device Address 基本操作 字节写入 分析手册 字节读取 随机读取 根据需要读取的地址进行读取 分析手册 读与写函数代码 实
  • 计算并输出给定正整数n的所有因子(不包括1和自身)之和

    国二有题目 请编写函数fun 该函数的功能是 计算并输出给定正整数n的所有因子 不包括1和自身 之和 规定n的值不大于1000 例如 在主函数中从键盘给n输入的值为856 则输出为 sum 763 代码如何完成呢 分析 1 输入的数字要是整
  • 内网渗透—红日靶场三

    文章目录 0x01 环境配置 0x02 Centos getshell 0x03 Centos提权 0x04 内网穿透 设置路由 0x05 内网穿透 设置代理 0x06 获取内网目标shell 通过smb拿shell 或者本地挂代理使用k8
  • Windows环境下编译C++版的MXNet问题处理

    最近涉及要在c 上部署人脸检测的算法 要在Windows环境下编译运行MXNet 对于不熟悉c 的小白的我真是一件又让人抓狂又掉头发的事情 网上关于c 的部署的帖子少之又少 加上又是第一次摸这些东西 所以出现的bug真的数不胜数 写这个bl
  • 数据结构与算法之二叉树: Leetcode 145. 二叉树的后序遍历 (Typescript版)

    二叉树的后序遍历 https leetcode cn problems binary tree postorder traversal 描述 给你一棵二叉树的根节点 root 返回其节点值的 后序遍历 示例 1 输入 root 1 null
  • 适合普通大学生的前端开发学习路线

    大家好 我是帅地 假如你没有明确的目标 或许可以按照我说的学习路线来学习一波 我写的每一份学习路线 不会很全面 因为我认为 东西列的太多 反而不利于新手的学习 所以我列举的 都是比较必要的知识 当你把这些知识学了的时候 我相信你不需要别人的
  • 前端基础_使用moveTo与lineTo路径绘制火柴人

    使用moveTo与lineTo路径绘制火柴人 接下来看一下除了arc方法以外 其他使用路径绘制图形时会使用到的方法 moveTo x y 不绘制 只是将当前位置移动到新的目标坐标 x y lineTo x y 不仅将当前位置移动到新的目标坐
  • 工控CTF(wp)

    GUET工控CTF 所见非真 异常的流量分析 黑客的攻击 黑客的大意 丢失的数据 凯撒的秘密 工程的秘密 S7协议分析 轻松时刻 打不开的压缩包 失控的遥控 病毒文件分析 OPC协议分析 sign in 随意记录一下这次CTF的解题步骤 比
  • 文章详情页 - 评论功能的实现

    目录 1 准备工作 1 1 创建评论表 1 2 创建评论实体类 1 3 创建 mapper 层评论接口和对应的 xml 实现 1 4 准备评论的 service 层 1 5 准备评论的 controller 层 2 总的初始化详情页 2 1
  • The Open Group 参考卡|《ArchiMate® 3.1 规范》中文版正式发布

    ArchiMate 规范 3 1 版在 3 0 1 版之间做了如下改动 增加了新的策略元素 价值流 为关联关系添加了可选的指示标记 改进了元模型和相关图形的组织结构 进一步完善和规范了关系的推导 除此之外 ArchiMate 规范 3 1
  • 全球及中国微电网市场规模容量及建设运营模式分析报告2021年版

    全球及中国微电网市场规模容量及建设运营模式分析报告2021年版 HS HS HS HS HS HS HS HS HS HS HS HS 修订日期 2021年11月 搜索鸿晟信合研究院查看官网更多内容 第一章 微电网相关概述 1 1 微电网概
  • pandas 取excel 中的某一列_别找了,这是 Pandas 最详细教程了

    点击上方 菜鸟编程大本营 选择 星标 公众号 重磅干货 第一时间送达 来源 机器之心 Python 是开源的 它很棒 但是也无法避免开源的一些固有问题 很多包都在做 或者在尝试做 同样的事情 如果你是 Python 新手 那么你很难知道某个
  • MySQL 如何优化慢查询?

    一 前言 在日常开发中 我们往往会给表加各种索引 来提高 MySQL 的检索效率 但我们有时会遇到明明给字段加了索引 并没有走索引的Case 进而导致 MySQL 产生慢查询 严重场景下 甚至出现主从延迟 数据库拖垮的极端事故 本文梳理出索