MySQL 如何优化慢查询?

这篇具有很好参考价值的文章主要介绍了MySQL 如何优化慢查询?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

在日常开发中,我们往往会给表加各种索引,来提高 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";
复制代码
  • 分析结果:

MySQL 如何优化慢查询?

  • 优化思路:

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

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

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

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

MySQL 如何优化慢查询?

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

  • 优化思路:

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

3. 索引列参与运算

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

MySQL 如何优化慢查询?

  • 优化思路:

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

4. 索引列使用了函数

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

MySQL 如何优化慢查询?

  • 优化思路:

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

5. 错误的 like 使用

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

MySQL 如何优化慢查询?

  • 优化思路:

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

6. 隐式类型转换

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

MySQL 如何优化慢查询?

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

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

MySQL 如何优化慢查询?

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

  • 优化思路:

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

7. OR 使用不当

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

MySQL 如何优化慢查询?

  • 优化思路:

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

8. 两个索引列做比较

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

MySQL 如何优化慢查询?

  • 优化思路:

不要对两个列做比较。

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

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

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

MySQL 如何优化慢查询?

  • 优化思路:

不要用 not。

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

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

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

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

MySQL 如何优化慢查询?

  • 优化思路:

非主键列,尽量不要用 order by。实在要用,需要先用 explain 分析是否可以走索引。
如果条件允许,可以用 ES 代替。文章来源地址https://www.toymoban.com/news/detail-451730.html

到了这里,关于MySQL 如何优化慢查询?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 物联网行业的革命:Web3 技术如何改变我们的日常生活

    物联网 (IoT) 是一个充满创新和潜力的领域,它将物理设备、传感器和互联网连接起来,实现智能化和自动化。 在过去几年中,从智能家居、智能城市到工业自动化,物联网技术已经渗透到了各个领域。然而,随着物联网设备和系统的数量不断增加,如何确保这些设备和系统

    2024年02月13日
    浏览(40)
  • 【JAVA面试】Mysql慢查询如何优化

    提示:文章先作为初版,等后续时间充足后,补充更深的内容 MySQL的慢查询是 指执行时间较长的SQL语句 ,可以根据执行时间超过预设阈值(如1秒)或返回的记录数超过预设阈值(如1000条)来进行定义。一般情况下**,慢查询是由于查询语句中使用了不恰当的索引、数据库结

    2024年02月03日
    浏览(32)
  • MySQL-如何定位慢查询SQL以及优化

    定位慢SQL可以通过慢查询日志来查看慢SQL,默认的情况下,MySQL数据库不开启慢查询日志(slow query log),需要手动把它打开 SET GLOBAL slow_query_log = ‘ON’; 查看下慢查询日志配置 SHOW VARIABLES LIKE ‘slow_query_log%’ slow_query_log:表示慢查询开启的状态 slow_query_log_file:表示慢查询日志

    2024年02月08日
    浏览(45)
  • MySQL中的in+子查询应该如何优化

    ☆* o(≧▽≦)o *☆嗨~我是小奥🍹 📄📄📄个人博客:小奥的博客 📄📄📄CSDN:个人CSDN 📙📙📙Github:传送门 📅📅📅面经分享(牛客主页):传送门 🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正! 📜 如果觉得内容还不错,欢迎点赞收藏关注哟!

    2024年01月19日
    浏览(33)
  • 如何对MySQL和MariaDB中的查询和表进行优化-提升查询效率

    MySQL和MariaDB是数据库管理系统的流行选择。两者都使用SQL查询语言来输入和查询数据。 尽管SQL查询是简单易学的命令,但并不是所有的查询和数据库函数都具有相同的效率。随着你存储的信息量的增长,如果你的数据库支持一个网站,随着网站的受欢迎程度的增加,这就变得

    2024年02月11日
    浏览(50)
  • MySQL中如何高效的实现模糊查询(附30条优化建议)

    在使用msyql进行模糊查询的时候,很自然的会用到like语句,通常情况下,在数据量小的时候,不容易看出查询的效率,但在数据量达到百万级,千万级的时候,查询的效率就很容易显现出来。这个时候查询的效率就显得很重要! 一般情况下like模糊查询的写法为(field已建立索

    2024年01月22日
    浏览(46)
  • MySQL Ruler mysql 日常开发规范

    MySQL View MySQL truncate table 与 delete 清空表的区别和坑 MySQL Ruler mysql 日常开发规范 MySQL datetime timestamp 以及如何自动更新,如何实现范围查询 MySQL 06 mysql 如何实现类似 oracle 的 merge into MySQL 05 MySQL入门教程(MySQL tutorial book) MySQL 04- EMOJI 表情与 UTF8MB4 的故事 MySQL Expression 1 of ORDE

    2024年04月10日
    浏览(34)
  • ChatGPT会对我们日常生活带来什么影响?这些技术会改变我们学习阅读工作方式吗?

    AI 这个话题很火,我也一直在关注着,很多人甚至觉得 AI 会改变世界,也许你会好奇:ChatGPT 会在三年内终结编程吗?AI有可能改变人的学习方式吗?AI 能否取代打工人?本文会对相关问题从我们可见日常问题进行解答。 希望从:AI 辅助提高了人的阅读效率吗、AI能帮助人更

    2024年02月03日
    浏览(63)
  • MySQL索引优化与查询优化

    MySQL中提高性能的一个最有效的方式是对数据表设计合理的索引。索引提供了访问高效数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。 使用索引可以快速地定位表中的某条记录,从而提高数据库查询的速度,提高数据库的性能。 如果查询时没

    2024年02月05日
    浏览(38)
  • mysql进阶-查询优化-慢查询日志

    日志对一个程序来说非常重要,他能帮助程序员在系统出现问题时快速定位问题, 慢查询日志 ( slow query log )是MySQL自带的几种日志文件中非常重要的一种日志(另还有错误日志、查询日志、二进制日志)。MySQL的慢查询日志是用于记录执行时间超过指定阈值的SQL查询语句的一

    2024年02月03日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包