前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL SQL优化快速定位案例 与 优化思维导图

MySQL SQL优化快速定位案例 与 优化思维导图

作者头像
AustinDatabases
发布于 2025-02-21 08:10:13
发布于 2025-02-21 08:10:13
11600
代码可运行
举报
文章被收录于专栏:AustinDatabasesAustinDatabases
运行总次数:0
代码可运行

MySQL的SQL优化相对于其他的数据库来说,应该是简单的主要的原因有以下

1 业务简单:使用MySQL的业务一般为互联网业务,且在拆库,分表的基础上语句必然变得简单,更多的复杂性是在程序和架构设计的层面。

2 单线程数据查询方式:单线程的数据查询方式更希望的是短小的SQL,这样避免复杂的SQL进行上下文切换中消耗更多的CPU,根据数据库的查询设计来说,MySQL还是希望短小精悍的SQL来进行业务的处理。

3 基于B+TREE的数据物理存储方式:如要发挥最大化的MySQL的查询性能,要利用MySQL查询中的物理属性来进行有的放矢的主键查询,对MYSQL更有利。

基于这些理念和MySQL的物理实现基础,大部分懂得道理的架构师和程序员,都不会给MySQL施加如ORACLE ,SQL SERVER,PostgreSQL类似的大型SQL语句。

但.....

很多MySQL的文盲,还在MySQL上施加了复杂的SQL语句,这就需要进行查询的优化和分析了。一般针对MySQL的分析我们怎么来做。(基于MySQL 版本差异大,MYSQL 5.6 5.7 8.0 9.0 ),这里按照向下兼容的方式,可能有些方法在高版本的MySQL已经非必须,快速查找问题的方法

我们以下面的一个语句作为一个例子;

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

MySQL [cloud]> explain SELECT                                                                                                                     
    ->   COUNT(*)
    -> FROM
    ->   (
    ->     SELECT
    ->       eb.slyGroupCo AS groupCo,
    ->       e.code AS entCo,
    ->       e.name AS entNa,
    ->       e.show_meth AS showMeth,
    ->       e.type + '' AS tag,
    ->       min(eb.BeginDa) AS beginda,
    ->       max(eb.EndDa) AS endda,  ,
    ->       GROUP_CONCAT(p.`Name`) AS pkgs
    ->     FROM
    ->       shopbi eb,
    ->       shop dt,
    ->       prodg p,
    ->       ent e,
    ->       bdf bd
    ->     WHERE
    ->       e.id = eb.enterpriseid
    ->       AND eb.id = dt.ShopBillID
    ->       AND dt.ProductPKGID = p.ID
    ->       AND eb.shopState = 0
    ->       AND eb.slymdCode IS NOT NULL
    ->       AND bd.DESC_ = 'S024739'
    ->       AND e.ORGID = bd.ID_
    ->       AND e.code LIKE '%ENT8853%'
    ->     GROUP BY
    ->       e.id,
    ->       eb.id
    ->     ORDER BY
    ->       max(eb.createDate) DESC
    ->   ) a;
+----+-------------+------------+--------+-----------------------------------------------------+--------------------+---------+---------------------------+-------+---------------------------------+
| id | select_type | table      | type   | possible_keys                                       | key                | key_len | ref                       | rows  | Extra                           |
+----+-------------+------------+--------+-----------------------------------------------------+--------------------+---------+---------------------------+-------+---------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                                                | NULL               | NULL    | NULL                      | 23072 | NULL                            |
|  2 | DERIVED     | p          | ALL    | PRIMARY                                             | NULL               | NULL    | NULL                      |   224 | Using temporary; Using filesort |
|  2 | DERIVED     | dt         | ref    | PRIMARY,FKD55C954DBC4687E4,FKD55C954DA4BA8D24       | FKD55C954DA4BA8D24 | 98      | cloudplat.p.ID            |   103 | Using index                     |
|  2 | DERIVED     | eb         | eq_ref | PRIMARY,FKEB7193FD322835EC,INDEX_SHOPBILL_SLYMDCODE | PRIMARY            | 98      | cloudplat.dt.ShopBillID   |     1 | Using where                     |
|  2 | DERIVED     | e          | eq_ref | PRIMARY,FKD027336111B1115F                          | PRIMARY            | 98      | cloudplat.eb.EnterpriseID |     1 | Using where                     |
|  2 | DERIVED     | bd         | eq_ref | PRIMARY                                             | PRIMARY            | 182     | cloudplat.e.ORGID         |     1 | Using where                     |
+----+-------------+------------+--------+-----------------------------------------------------+--------------------+---------+---------------------------+-------+---------------------------------+
6 rows inset (0.002 sec

1 看到一个MySQL的语句,首先我先看type,尤其复杂的SQL,先看type这里有没有 ALL, 在type中ALL的字段出现,说明在这部分存在全表扫描,那么首先我们就要先分析这块的部分是否有问题。在查看了表信息后,发现对应的索引和主键都是齐全的,关键为什么走了ALL,主要的原因是一个表中的行数非常的少,且与另一个表连接是主外键关系,所以必然对于小表走了全表扫描,所以排除了这部分索引有问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

MySQL [cloud]> select count(*) from product;
+----------+
| count(*) |
+----------+
|      261 |
+----------+
1 row in set (0.002 sec)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

MySQL [cloudplat]> select count(*) from shopbi;
+----------+
| count(*) |
+----------+
|   935312 |
+----------+
1 row in set (1.174 sec)

下面想快速的对SQL进行优化,则需要使用第二种方案,针对核心表进行分析,这里一眼可以分析出,这个SQL中的核心表是eb,因为eb参与了与多个表之间的关联且通过它来进行where条件的给出是最多的。

eb表的条件

e.id = eb.enterpriseid

eb.id = dt.ShopBillID

eb.id = dt.ShopBillID

eb.shopState = 0

eb.slymdCode IS NOT NULL

max(eb.createDate) DESC

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

CREATE TABLE `eb` (
  `id` varchar(32) NOT NULL COMMENT '主键',
  `shopCode` varchar(32) DEFAULT NULL COMMENT 
  `EnterID` varchar(32) DEFAULT NULL COMMENT 
  `createDate` datetime DEFAULT NULL COMMENT
  `modate` datetime DEFAULT NULL COMMENT 
  `shopId` varchar(32) DEFAULT NULL COMMENT 
  `shopState` int(1) DEFAULT '0' COMMENT
  PRIMARY KEY (`id`),
  KEY `FKEB7322835EC` (`EnterpriseID`),
  KEY `FKEB7193AAD` (`createUser`),
  KEY `INDEX_SHOPBILL_SLYMDCODE` (`slymdCode`) USING BTREE,
  KEY `INDEX_SHOPBILL_SHOPID` (`shopId`) USING BTREE,
  CONSTRAINT `FKEB719335EC` FOREIGN KEY (`EnteiseID`) REFERENCES `enterprise` (`ID`),
  CONSTRAINT `FKEB71D131AAD` FOREIGN KEY (`creaUser`) REFERENCES `bdf2` (`USERNAME_`)

eb表的条件

e.id = eb.enterseid

有索引

eb.id = dt.ShopBiID

主键

eb.shate = 0

无索引

eb.slymdCode IS NOT NULL

有索引

max(eb.creatte) DESC

无索引

同时经过验证,虽然shopState无索引,但这里 shopstate过滤的数据并不多,只占本身表的10%,而90%的数据都是需要的。所以这里并不能再这个表进行更多的优化。同时经过语句的分析,发现这里有一个表的条件可以过滤更多的数据。这个表就是bd, 经过再次分析bd表,其中这里有一个关键,可以大量减少e表的扫描行数,而e表的扫描行数减少,将大幅度的减少eb表的扫描行数,而关键在于bd表的DESC_ 没有索引,而导致全表扫描与其他表进行比对。所以随即对表 bd添加索引。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

| bdf2_dept | CREATE TABLE `bdf2_dept` (
  `ID_` varchar(60) NOT NULL,
  `COMP_ID_` varchar(60) DEFAULT NULL,
  `CREA_DATE_` date DEFAULT NULL,
  `DESC_` varchar(120) DEFAULT NULL,
  `NA_` varchar(60) DEFAULT NULL,
  `PAT_ID_` varchar(60) DEFAULT NULL,
  PRIMARY KEY (`ID_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row inset (0.001 sec)

MySQL [cloudplat]> select count(*) from bdf2;
+----------+
| count(*) |
+----------+
|     1506 |
+----------+
1 row inset (0.002 sec)

ALTER TABLE `cloud`.`bdf2` ADD INDEX `idx_DESC` (`DESC`);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

MySQL [cloudplat]> select count(*) from ense;
+----------+
| count(*) |
+----------+
|    30787 |
+----------+
1 row in set (0.026 sec)

在添加完索引后,整体SQL运行的效率提高了 440倍,从原来的4秒,到现在的0.009秒。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

MySQL [cloud]> ALTER TABLE `cloud`.`bdf2` ADD INDEX `idx_DESC` (`DESC_`);
Query OK, 0 rows affected (0.009 sec)
Records: 0  Duplicates: 0  Warnings: 0

MySQL [cloudplat]> explain SELECT
    ->   COUNT(*)
    -> FROM
    ->   (
    ->     SELECT
    ->       eb.slyGroupCode AS groupCode,
    ->       e.code AS entCode,
    ->       e.name AS entName,
    ->       e.show_method AS showMethod,
    ->       e.type + '' AS tag,
    ->       min(eb.BeginDate) AS begindate,
    ->       max(eb.EndDate) AS enddate,
    ->       e.dbname AS dbname,
    ->       e.domainname AS domainname,
    ->       eb.shopCode AS shopCode,
    ->       eb.shopName AS shopName,
    ->       eb.linkman AS linkman,
    ->       eb.slymdCode AS slymdCode,
    ->       eb.phone AS phone,
    ->       eb.email AS email,
    ->       eb.remark AS remark,
    ->       GROUP_CONCAT(p.`Name`) AS pkgs
    ->     FROM
    ->       sholl eb,
    ->       sholldt dt,
    ->       propkg p,
    ->       entise e,
    ->       bdf2 bd
    ->     WHERE
    ->       e.id = eb.entiseid
    ->       AND eb.id = dt.ShllID
    ->       AND dt.ProdGID = p.ID
    ->       AND eb.shate = 0
    ->       AND eb.slymdCode IS NOT NULL
    ->       AND bd.DESC_ = 'S739'
    ->       AND e.ORGID = bd.ID_
    ->       AND e.code LIKE '%EN53%'
    ->     GROUP BY
    ->       e.id,
    ->       eb.id
    ->     ORDER BY
    ->       max(eb.createDate) DESC
    ->   ) a;
+----+-------------+------------+--------+--------------------------------------------------------------------------------+--------------------+---------+---------------------------+------+-----------------------------------------------------------+
| id | select_type | table      | type   | possible_keys                                                                  | key                | key_len | ref                       | rows | Extra                                                     |
+----+-------------+------------+--------+--------------------------------------------------------------------------------+--------------------+---------+---------------------------+------+-----------------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL                                                                           | NULL               | NULL    | NULL                      |   90 | NULL                                                      |
|  2 | DERIVED     | bd         | ref    | PRIMARY,idx_DESC                                                               | idx_DESC           | 363     | const                     |    1 | Using where; Using index; Using temporary; Using filesort |
|  2 | DERIVED     | e          | ref    | PRIMARY,FKD0211B1115F                                                     | FKD06111B1115F | 99      | cloud.bd.ID_          |   15 | Using index condition; Using where                        |
|  2 | DERIVED     | eb         | ref    | PRIMARY,FKE835EC,INDEX_SHOPBILL_SLYMDCODE,idx_EnterpriseID_shopState | FKEB7193FD322835EC | 99      | cloudplat.e.ID            |    2 | Using where                                               |
|  2 | DERIVED     | dt         | ref    | PRIMARY,FKDDBC4687E4,FKD55C9A8D24                                  | FKD55C4687E4 | 98      | cloudplat.eb.id           |    3 | Using index                                               |
|  2 | DERIVED     | p          | eq_ref | PRIMARY                                                                        | PRIMARY            | 98      | cloud.dt.ProdID |    1 | NULL                                                      |
+----+-------------+------------+--------+--------------------------------------------------------------------------------+--------------------+---------+---------------------------+------+-----------------------------------------------------------+
6 rows inset (0.002 sec)

MySQL [cloudplat]> SELECT
    ->   COUNT(*)
    -> FROM
    ->   (
    ->     SELECT
    ->       eb.slyGroupCode AS groupCode,
    ->       e.code AS entCode,
    ->       e.name AS entName,
    ->       e.show_method AS showMethod,
    ->       e.type + '' AS tag,
    ->       min(eb.BeginDate) AS begindate,
    ->       max(eb.EndDate) AS enddate,
    ->       e.dbname AS dbname,
    ->       e.domainname AS domainname,
    ->       eb.shopCode AS shopCode,
    ->       eb.shopName AS shopName,
    ->       eb.linkman AS linkman,
    ->       eb.slymdCode AS slymdCode,
    ->       eb.phone AS phone,
    ->       eb.email AS email,
    ->       eb.remark AS remark,
    ->       GROUP_CONCAT(p.`Name`) AS pkgs
    ->     FROM
    ->       shopbill eb,
    ->       shopbilldt dt,
    ->       productpkg p,
    ->       enterprise e,
    ->       bdf2_dept bd
    ->     WHERE
    ->       e.id = eb.enteseid
    ->       AND eb.id = dt.ShllID
    ->       AND dt.ProdGID = p.ID
    ->       AND eb.shate = 0
    ->       AND eb.slymdCode IS NOT NULL
    ->       AND bd.DESC_ = 'S0739'
    ->       AND e.ORGID = bd.ID_
    ->       AND e.code LIKE '%E53%'
    ->     GROUP BY
    ->       e.id,
    ->       eb.id
    ->     ORDER BY
    ->       max(eb.crate) DESC
    ->   ) a;
+----------+
| COUNT(*) |
+----------+
|       14 |
+----------+
1 row inset (0.009 sec)

下面是一个简单的MySQL优化的思路(初级版)

结语:SQL的优化也是分等级,快速的优化解决大部分的问题,针对少量的SQL难点进行细致的优化和问题的解决,如逻辑法,业务法,SQL改写法,HINT 重定index 大法,后期有了相应的案例可以继续和大家进行探讨。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AustinDatabases 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
将MySQL去重操作优化到极致
源表t_source结构如下: item_id int, created_time datetime, modified_time datetime, item_name varchar(20), other varchar(20)
用户1148526
2019/08/14
8K0
轻松搞懂mysql的执行计划,再也不怕sql优化了
近期要做一些sql优化的工作,虽然记得一些常用的sql 优化技巧,但是在工作中还是不够,所以需要借助工具的帮助,数据库的解释计划阐明了sql的执行过程,展示了执行的细节,我们只要根据数据库告诉我们的问题按图索骥的分析就好了,但是解释计划也不是那么容易看懂,所以今天就学习下解释计划的一些参数的意义。
香菜聊游戏
2021/10/20
7450
SQL优化之踩过的坑
正看资料看的过瘾,突然收到报警,说服务器负载太高,好吧,登录服务器看看,我擦嘞,还能不能愉快的玩耍了?下面是当时的负载情况 看见mysql使用cpu已经到了2000,io没有等待。 说明应该没有大的临
小小科
2018/05/03
6910
SQL优化之踩过的坑
MySQL SQL优化
如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使用MySQL数据库提供的load指令进行插入。操作如下:
用户9615083
2022/12/25
1.9K0
MySQL SQL优化
MySQL进阶之索引
索引是对数据库表中一个或多个列(例如,employee 表的姓名 (name) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
测试小兵
2019/11/19
4730
SQL优化 21 连击 + 思维导图
比如,存储字符串“101”,对于char(10),表示你存储的字符将占10个字节(包括7个空字符),在数据库中它是以空格占位的,而同样的varchar2(10)则只占用3个字节的长度,10只是最大值,当你存储的字符小于10时,按实际长度存储。
Java小咖秀
2022/09/23
8470
如何定位及优化SQL语句的性能问题
在现如今的软件开发中,关系型数据库是做数据存储最重要的工具。无论是Oracale还是Mysql,都是需要通过SQL语句来和数据库进行交互的,这种交互我们通常称之为CRUD。在CRUD操作中,最最常用的也就是Read操作了。而对于不同的表结构,采用不同的SQL语句,性能上可能千差万别。本文,就基于MySql数据库,来介绍一下如何定位SQL语句的性能问题。
咸鱼学Python
2020/07/21
1.4K0
【MySQL高级】SQL优化
因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。
陶然同学
2023/02/24
6340
【MySQL高级】SQL优化
sql优化40秒到0.1秒的奥秘
经和运维配合查看,发现是SQL语句问题,有个sql查询脚本执行竟然消耗了40秒,我拿出来自己执行发现亦是如此。
灬沙师弟
2023/09/06
3380
sql优化40秒到0.1秒的奥秘
MySQL中怎样快速找出超长索引
想要查找哪些索引太长了,这个SQL在5.7下跑的特别慢,8.0则挺快的,帮看下有啥优化方案没
老叶茶馆
2021/02/23
1.8K0
MySQL中怎样快速找出超长索引
mysql-索引
数据库中专门用于帮助用户快速查找数据的一种数据结构。类似于字典中的目录,查找字典内容时可以根据目录查找到数据的存放位置吗,然后直接获取
py3study
2018/08/03
6790
7种SQL走索引or不走索引的优化,你竟然还不了解?
在传统的系统应用程序中我们通常都会和数据库建立连接进行数据的读写操作,为了减少连接数据库造成的资源消耗于是有了数据库连接缓冲池。在此基础上,SQL 语句的优化对于研发人员也是非常重要的,高效的 SQL 语句经常会给使一个业务逻辑的接口响应速度变得非常快。所以本篇小编将主要从 SQL 语句的优化给出一些建议以及如何使用 SQL 语句里面的关键字等才能使 SQL 的执行效率相对提升,并且分享一份MySQL优化学习笔记,希望给研发人员在编写 SQL 语句时能有一些帮助。
Java程序猿
2021/06/01
7.8K1
MySQL进阶笔记-3(MySQL优化)
在应用的的开发过程中,由于初期数据量小,开发人员写 SQL 语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的 SQL 语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化,本章将详细介绍在 MySQL 中优化 SQL 语句的方法。
千羽
2021/01/14
4880
MySQL进阶笔记-3(MySQL优化)
[MySQL] SQL优化案例1
原始SQL如下,MySQL版本5.7.19。执行时间1小时以上无法出结果 SELECT * FROM ( SELECT a.*, e.PAGY_STAT, b.brname, c.SETL_TYPE, c.SETL_SYMBOL, c.SETL_CYCLE, c.spec_Setl_Day, c.SETL_ACCT_NAME,
夜半钟鸣
2021/02/25
3700
【MySQL 8.0神器揭秘】派生表条件下推——让你的SQL飙车不再是梦想!
最近遇到了不少MySQL性能优化的案例,都和子查询有关,今天就这个话题做一定的分析。
MySQLSE
2024/01/22
5220
【MySQL 8.0神器揭秘】派生表条件下推——让你的SQL飙车不再是梦想!
Mysql高级5-SQL优化
    如果有多条数据需要同时插入,不要每次插入一条,然后分多次插入,因为每执行一次插入的操作,都要进行数据库的连接,多个操作就会连接多次,而一次批量操作只需要连接1次
Se7eN_HOU
2023/08/02
3620
Mysql高级5-SQL优化
SQL优化完整详解
通过 SHOW STATUS 可以提供服务器状态信息,也可以使用 mysqladmin extende d-status 命令获得。 SHOW STATUS 可以根据需要显示 session 级别的统计结果和 global级别的统计结果。
黄规速
2022/04/14
1.4K0
SQL优化完整详解
SQL学习笔记五之MySQL索引原理与慢查询优化
一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重。说起加速查询,就不得不提到索引了。
Jetpropelledsnake21
2019/02/15
9090
Explain 执行计划 和 SQL优化
在分析查询性能时,考虑EXPLAIN关键字同样很管用。EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作、以及MySQL成功返回结果集需要执行的行数。explain 可以帮助我们分析 select 语句,让我们知道查询效率低下的原因,从而改进我们查询,让查询优化器能够更好的工作,可以帮助选择更好的索引和写出更优化的查询语句。
星哥玩云
2022/08/17
7440
Explain 执行计划 和 SQL优化
SQL优化思路+经典案例分析
SQL调优这块呢,大厂面试必问的。最近金九银十嘛,所以整理了SQL的调优思路,并且附几个经典案例分析。
捡田螺的小男孩
2023/02/24
1K0
SQL优化思路+经典案例分析
相关推荐
将MySQL去重操作优化到极致
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档