记一次mysql多表查询(left jion)优化案例
一次mysql多表查询(left jion)优化案例
在新上线的供需模块中,发现某一个查询按钮点击后,出不来结果,找到该按钮对应sql手动执行,发现需要20-30秒才能出结果,所以服务端程序判断超时,故先不显示结果
以下是对这条查询的优化记录
1 数据库配置
数据库配置:4C8G
主表数据:3W+
2 sql语句
提取sql语句,简化如下
SELECT
taba.id,
taba.title,
taba.type,
taba.end_time,
tabb.username,
tabc.orgname
FROM
taba
LEFT JOIN tabd ON tabd.info_id = taba.id
LEFT JOIN tabe ON tabe.sdo_id = taba.id
LEFT JOIN tabb ON tabb.id = taba.creator
LEFT JOIN tabc ON tabc.id = taba.organization_id
WHERE
taba.`STATUS` = 'PUBLISH'
AND tabd.type = 'INDEX'
AND tabd.`VALUE` = '1'
AND taba.info_type = 'SUPPLY'
GROUP BY
taba.id
ORDER BY
taba.create_time DESC
LIMIT 100
3 优化记录
3.1 数据库索引
首先第一反应,查sql是否走了索引
EXPLAIN
select ......
从索引检查结果发现
tabe
只有主键索引,没有sdo_id
的索引
经过确定sdo_id
是通过uuid制作,重复数很少,可以增加上索引- 其他条件虽然也没走索引,但是属于枚举值,重复性高,没有加索引的条件
经过添加索引,数据查询时间降低到3秒以内,所以正确的索引才是王道
3.2 返回数据限制
经过与开发人员沟通,确定可以每次只取10条数据,所以要求他们更改limit语句限制为limit 10
经过修改limit语句,数据库直插时间已经变味1.7秒
3.3 spring框架错误的conut *
经过前两部优化,按理2秒左右app就能显示数据,但是时间上却需要4秒钟
通过sql慢查询日志,发现在这条sql执行前,spring框架自动执行了一个select count(0) from (......)
的操作来做分页,但是所以导致查询时间是理论上的2倍
再次与开发确定,不用框架的自动分页功能,改为代码层手动分页
结果修改框架的分页,app查询时间达到2秒内,已基本得到解决
3.4 极限优化limit
查询优化到2秒,已基本可以接受,但是先到数据才3万多行,感觉还是不能接受,继续找原因,发现如下:
- 3万+数据,但是sql执行结果却显示扫描了100多万行数据
观察sql语句,可以发现是先做了多次left join
后,对结果取limit
,那能不能先取limit 10
再进行查询呢,于是把sql优化如下
SELECT
taba.id,
taba.title,
taba.type,
taba.end_time,
tabb.username,
tabc.orgname
FROM
taba
LEFT JOIN tabd ON tabd.info_id = taba.id
LEFT JOIN tabe ON tabe.sdo_id = taba.id
LEFT JOIN tabb ON tabb.id = taba.creator
LEFT JOIN tabc ON tabc.id = taba.organization_id
WHERE
tabd.type = 'INDEX'
AND tabd.`VALUE` = '1'
AND taba.id IN (
SELECT * FROM
( SELECT id FROM taba WHERE `STATUS` = 'PUBLISH'
AND info_type = 'SUPPLY'
ORDER BY taba.create_time DESC LIMIT 10 ) AS tmp
)
优化方法:
- 将limit语句通过子查询放入where条件中
- sql将先执行子查询获取10条
id
数据 - 让后将10条
id
拿去前面做join
优化结果
- sql执行时间达到0.117秒,再一次质的飞跃
- 基本做到秒加载,点击按钮,一秒内出结果
3.4.1
第二天一觉醒来,觉得这个sql还有值得优化的地方,于是分别提取出各语句执行后,发现耗时最长的是limit条件,耗时0.09s
优化方法
- 查找发现原因是
order by
条件create_time
列未加索引,导致做了一次全表扫描 - 于是增加上
create_time
索引
优化结果
- sql执行时间变为0.068s
- 再次说明正确的索引才是王道
3.5 优化后记
其实sql中还有几个可以优化的地方,比如:
- 4个
left join
中的3个可以改成inner join
- 原语句的
group by
,经测试改掉可优化0.3秒(1.7秒处) - limit语句可以放到from处先处理等
但是:
- sql优化是长期的过程
- 优先解决影响业务的慢查询
- 优先解决占时间比例大的慢查询
- 咱是运维,不是DBA,还有高可用等着我玩
- 因此已经达到要求,甚至超额完成,就不用再管芝麻了
记一次mysql多表查询(left jion)优化案例的更多相关文章
- MySQL 回表查询 & 索引覆盖优化
回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...
- MySQL多表查询之外键、表连接、子查询、索引
MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...
- Mysql 单表查询 子查询 关联查询
数据准备: ## 学院表create table department( d_id int primary key auto_increment, d_name varchar(20) not nul ...
- (转)Mysql 多表查询详解
MySQL 多表查询详解 一.前言 二.示例 三.注意事项 一.前言 上篇讲到mysql中关键字执行的顺序,只涉及了一张表:实际应用大部分情况下,查询语句都会涉及到多张表格 : 1.1 多表连接有 ...
- MySQL多表查询回顾
----------------------siwuxie095 MySQL 多表查询回顾 以客户和联系人为例(一对多) 1.内连接 /*内连接写法一*/ select * from t_custom ...
- python 3 mysql 单表查询
python 3 mysql 单表查询 1.准备表 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职 ...
- python3 mysql 多表查询
python3 mysql 多表查询 一.准备表 创建二张表: company.employee company.department #建表 create table department( id ...
- Mysql 单表查询-排序-分页-group by初识
Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...
- Mysql 单表查询where初识
Mysql 单表查询where初识 准备数据 -- 创建测试库 -- drop database if exists student_db; create database student_db ch ...
随机推荐
- h5样式
禁止长按默认事件 安卓(android): window.ontouchstart = function(e) { e.preventDefault(); }; 苹果(ios): -webkit-to ...
- Button相关设置
2020-03-11 每日一例第4天 1.添加按钮1-6,并修改相应的text值: 2.窗体Load事件加载代码: private void Form1_Load(object sender, Ev ...
- Object.keys()方法
一.定义和用法 返回对象的可枚举属性和方法的名称.二.参数 obj:要返回器枚举自身属性的对象.三.返回值 返回一个所有元素为字符串的数组,其元素来自于从给定的obj里可直接枚举的属性.这些属性的顺序 ...
- 《自拍教程46》Python_adb自动拍照100张
Android手机测试, 涉及照相机(Camera)应用程序的稳定性测试的用例, 需要涉及100张照片的拍照自动化测试. 准备阶段 先清理老照片,照片一般存放在/scard/DCIM目录下 adb s ...
- 【opencv系列02】OpenCV4.X图像读取与显示
一.读取图片 opencv中采用imread() 函数读取图像 imread(filename, flags=None) filename 图片的路径 flags 图像读取方式 ● c ...
- 《Python学习手册 第五版》 -第17章 作用域
上一章的是函数的基础,因为函数在运用过程中,是可以嵌套的,函数中是会涉及到变量的,为了明确各自变量的使用范围,系统是有一套规则或者原则的,这就是作用域的概念 本章重点内容 1.作用域:作用域的概念 2 ...
- Abp 抛出详细异常
Abp在默认情况下,只要后端抛出异常,一概过滤为服务器错误并弹出,这样并不方便调试,这个时候需要开启一个开关即可: 在模块预初始化PreInitialize中开启,代码如下: , 这样就可以看到详细的 ...
- 玩转控件:封装Dev的LabelControl和TextEdit
俗话说的好:"工欲善其事必先利其器",作为软件攻城狮也是同样道理,攻城狮开发的软件目的是简化客户的操作,让客户动动手指就可以完成很多事情,减少人力成本.这也是系统/软件存在的目的. ...
- 【转】Kerberos简介
Kerberos协议: Kerberos协议主要用于计算机网络的身份鉴别(Authentication), 其特点是用户只需输入一次身份验证信息就可以凭借此验证获得的票据(ticket-grantin ...
- 贵州省网络安全知识竞赛个人赛Writeup
首先拖到D盾扫描 可以很明显的看出来确实就是两个后门 0x01 Index.php#一句话木马后门 0x02 About.php#文件包含漏洞 都可以很直观的看出来非常明显的漏洞,第一个直接就是eva ...