首页 > 数据库 >MySQL慢查询(上):你知道为啥会慢么?

MySQL慢查询(上):你知道为啥会慢么?

时间:2022-11-11 13:36:06浏览次数:46  
标签:为啥 MySQL 会慢 查询 索引 SQL 执行 id


正文共: 2487字  6图  预计阅读时间: 7分钟

发现的一些问题

问题1

在过去的半年时间里,研发团队内部尝试抓了一波儿慢查询SQL跟进处理率。发现有些同学对于慢查询处理的思路就是看看有没有用到索引,没有用到就试图加一个,实在不行就甩锅给这种情况是历史设计问题或者自行判定为用户特殊操作下触发的小概率事件,随即便申请豁免掉... 其实问题没有根本上解决。

问题2

还有就是网络上经常可以看到一些类似这样的文章:

“慢SQL性能优化大全”

“慢SQL性能优化看这篇就够了”...  

其实内容大同小异,要么建议加索引,要么建议重写SQL....

怎么说呢?知识点是对的,但不全面,这个很容易误导新同学,哈哈哈。

本文初衷

在业务项目发展过程中,我们常常会面对要处理 MySQL 慢查询问题,那我们应该如何分析解决问题呢?

部分同学在处理MySQL慢查询时候主要思路是加索引来解决,确实加索引是一个很好的解决问题的手段,但不是全部。既然慢查询作为问题,那就需要明确问题发生原因,和解决问题路径分析, 授人以鱼不如授人以渔,让我们一起来解锁 ???? 下MySQL处理慢查询的正确姿势。

本文计划主要让大家搞明白查询SQL为什么会变慢,废话不多说,直接开干~

写在前面

在业务项目发展过程中,我们常常会面对要处理 MySQL 慢查询问题,那我们应该如何分析解决问题呢?

部分同学在处理MySQL慢查询时候主要思路是加索引来解决,确实加索引是一个很好的解决问题的手段,但不是全部。既然慢查询是问题,那就需要明确问题发生原因,和解决问题路径分析。我们一起来get下MySQL慢查询的正确姿势。

一、查询SQL执行到底经历了什么?

首先需要明确:一个查询SQL的执行到底经历了什么?

MySQL慢查询(上):你知道为啥会慢么?_mysql

数据库执行SQL的大致流程如下:

  • 建立与MySQL服务器连接(基础)
  • 客户端发送查询SQL到数据库,数据库验证是否有执行的权限
  • MySQL服务器先检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果,否则继续流转;
  • MySQL服务器语法解析器,进行词法与语法分析,预处理
  • 流转至查询优化器生成执行计划
  • 根据生成的执行计划,调用存储引擎暴露的API来执行查询
  • 将查询执行结果返回给客户端
  • 关闭MySQL连接

具体执行过程可能会因MySQL服务器具体配置和执行场景有一些差异。

1)如未开启应用查询缓存,则直接忽略查询缓存的检查;

2)执行过程中,如同时对于被扫描的行可能加锁,同时也可能会被其他sql阻塞

二、查询SQL为什么会慢?

我们可以把查询SQL执行看做是一个任务的话,那它是由一些列子任务组成的,每个子任务都存在一定的时间消耗。通常情况下,导致慢查询最根本的问题就是需要访问的数据太多,导致查询不可避免的需要筛选大量的数据。

面对慢查询,我们需要注意以下两点:

1)查询了过多不需要的数据

2)扫描了额外的记录

2.1 查询了过多不需要的数据

MySQL并不是只返回需要的数据,实际上会返回全部结果集再进行计算。

尤其是多表关联查询 select * 的情况,我们是不是真的需要全部的列呢?如果不是,那我们直接指定对应字段就好了。

例如我们要查询用户关联订单下的商品信息,如下所示:

SELECT *
FROM users
LEFT JOIN orders ON orders.user_id = users.user_id
LEFT JOIN goods ON goods.good_id = orders.good_id
WHERE users.name = 'zhangsan';

这将返回三个表的全部数据列,可以调整为仅取需要的列:

SELECT goods.title, goods.description
FROM users
LEFT JOIN orders ON orders.user_id = users.user_id
LEFT JOIN goods ON goods.good_id = orders.good_id
WHERE users.name = 'zhangsan';

取出全部列,会让优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的I/O、内存和CPU的消耗。

2.2 扫描了额外的记录

此种情况大部分属于索引应用不当造成的(包括:该建的索引没有建,或者未应用到最佳索引)。

示例表结构如下:

CREATE TABLE `test_table` (
`name` varchar(32) DEFAULT NULL,
`desc` varchar(32) DEFAULT NULL,
`age` int(16) DEFAULT NULL,
`id` bigint(11) DEFAULT NULL,
KEY `idx_age` (`age`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

存在索引 `idx_age` 的情况下,查询执行计划如下:

EXPLAIN SELECT * FROM test_table WHERE age = 10;

MySQL慢查询(上):你知道为啥会慢么?_mysql_02

预估访问1行数据即可命中数据,如删除有效索引 `idx_age` 后则会变成全表扫描(ALL),预估需要扫描121524条记录才能完成这个查询,如下图所示:

MySQL慢查询(上):你知道为啥会慢么?_慢查询_03

小结

根据梳理 MySQL中的 SQL执行过程我们发现,任何流程的执行都存在其执行环境和规则,其实产生慢SQL的本质是:我们没有按照数据库的要求方式来执行SQL。

主要导致慢查询最根本的问题就是需要访问的数据太多,导致查询不可避免的需要筛选大量的数据。



最后,欢迎大家持续关注~

MySQL慢查询(上):你知道为啥会慢么?_编程语言_04


公号文章主要来自于个人日常工作问题总结思考,相信问题及解决方案均具有普适性,希望同大家一起学习成长。

同时和一些志同道合的小伙伴们建了一个技术交流群,一起探讨技术、共同学习进步


Thanks for reading!

标签:为啥,MySQL,会慢,查询,索引,SQL,执行,id
From: https://blog.51cto.com/u_15107509/5844754

相关文章

  • 踩坑 MySQL 索引,看看你真的会用吗?
    关于MySQL索引,对于研发同学,尤其是后端研发同学,一定不会陌生。我们工作中经常会用到MySQL数据库,就肯定会经常用到性能优化方面的设计和考量,常常用涉及到MySQL索引。但......
  • 用实例带你了解 MySQL 全局锁
    MySQL全局锁会申请一个全局的读锁,对整个库加锁。全局锁的一般使用场景是:全局逻辑备份。全局锁的实现方式有两种://第一种方法Flushtableswithreadlock(FTWRL)//第二种方法......
  • 【MySQL(八)】一致性非锁定读 锁定读 解析
    一致性非锁定读与锁定读的区别主要针对的是读操作在加锁方式上的差别。这里先看下锁的分类吧。mysql的行锁分为读锁与写锁。读锁即S锁,也叫共享锁,当事务读取一行数据时,会尝试......
  • 【MySQL(三)】buffer pool相关
    bufferpool是一种减少磁盘io读的机制,原理是将访问过的磁盘数据暂留在内存中,这样下次访问相同的数据就不需要读磁盘了。这个思想在平时的开发中,也经常用到,比如我们通常会在......
  • 【MySQL(十九)】复制 过程
    主库将数据写入本地binlog文件中;从库连接,指定起始位置;主库的binlogdump线程开始将binlog内容发送给从库;从库的io线程将收到的binlog内容写入到本地的relaylog中;从库的sql......
  • MySQL启动报错[ERROR] InnoDB: Trying to access page number 4294967295 in space 0,
    这篇文章是原来的《记一次mysql故障处理》,但是随着mysql问题越来越多,我感觉还是集合到一篇里面比较好,也方便之后问题复现的查找一、记一次mysql故障处理最近遇到的问......
  • MySQL备库复制延迟的原因及解决办法【转】
    背景今天有同事问我主从复制延迟会影响高可用切换的RTO怎么办,这个不需要做实验,我可以直接回答,所以有了以下赶鸭子的文章,都是一线运维经验之谈,建议四连:点赞、收藏、转发......
  • 【mysql】索引
    mysql的索引是由引擎决定的。1.哈希索引,这个和哈希表是一样的原理,从关键字的哈希函数值映射到物理位置。特点是只能针对等于的查询,效率很高。2.B树索引,为关键字维护一棵b树,......
  • 为啥in_array(0, ['a', 'b', 'c']) 会返回true?
     在具体PHP编码过程中,总会出现一些我们认为不可能的情况,如下几例:in_array(0,['a','b','c'])//返回bool(true),也就相当于数组中有0array_search(0,['a','b','c......
  • CentOS7 卸载 mysql8
    1、停掉mysql服务servicemysqlstop查看已安装的mysqlrpm-qa|grepmysql2、卸载mysql服务yumremovemysql-servermysqlmysql-libs再次查看是否还有......