一次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 ......

从索引检查结果发现

  1. tabe只有主键索引,没有sdo_id的索引

    经过确定sdo_id是通过uuid制作,重复数很少,可以增加上索引
  2. 其他条件虽然也没走索引,但是属于枚举值,重复性高,没有加索引的条件

经过添加索引,数据查询时间降低到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)优化案例的更多相关文章

  1. MySQL 回表查询 & 索引覆盖优化

    回表查询 先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据 建表示例 mysql> create table user( -> id int(10) auto_incre ...

  2. MySQL多表查询之外键、表连接、子查询、索引

    MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...

  3. Mysql 单表查询 子查询 关联查询

    数据准备: ## 学院表create table department( d_id int primary key auto_increment, d_name varchar(20) not nul ...

  4. (转)Mysql 多表查询详解

    MySQL 多表查询详解 一.前言  二.示例 三.注意事项 一.前言  上篇讲到mysql中关键字执行的顺序,只涉及了一张表:实际应用大部分情况下,查询语句都会涉及到多张表格 : 1.1 多表连接有 ...

  5. MySQL多表查询回顾

    ----------------------siwuxie095 MySQL 多表查询回顾 以客户和联系人为例(一对多) 1.内连接 /*内连接写法一*/ select * from t_custom ...

  6. python 3 mysql 单表查询

    python 3 mysql 单表查询 1.准备表 company.employee 员工id id int 姓名 emp_name varchar 性别 sex enum 年龄 age int 入职 ...

  7. python3 mysql 多表查询

    python3 mysql 多表查询 一.准备表 创建二张表: company.employee company.department #建表 create table department( id ...

  8. Mysql 单表查询-排序-分页-group by初识

    Mysql 单表查询-排序-分页-group by初识 对于select 来说, 分组聚合(((group by; aggregation), 排序 (order by** ), 分页查询 (limi ...

  9. Mysql 单表查询where初识

    Mysql 单表查询where初识 准备数据 -- 创建测试库 -- drop database if exists student_db; create database student_db ch ...

随机推荐

  1. Redis06——Redis到底能用在什么地方(上)

    之前我们介绍了一些列关于Redis的数据结构.持久化.过期&淘汰策略.集群化等知识点,感兴趣的小伙伴可以在文章的末尾查看往期内容.今天将为大家带来Redis的应用.由于本篇文章较长,所以将拆分 ...

  2. Simulink仿真入门到精通(八) M语言对Simulink模型的自动化操作及配置

    8.1 M语言控制模型的仿真 M语言与Simulink结合的方式: 在Simulink模型或模块中使用回调函数 在M语言中调用与模型相关的命令,控制模型的建立,设置模块的属性,增删信号线,以及运行模型 ...

  3. drf分页功能

    什么是restful规范 是一套规则,用于程序之间进行数据交换的约定. 他规定了一些协议,对我们感受最直接的的是,以前写增删改查需要写4个接口,restful规范的就是1 个接口,根据method的不 ...

  4. 关于使用 Laravel 服务容器的优势介绍

    如果说laravel框架的核心是什么,那么无疑是服务容器.理解服务容器的概念,对于我们使用laravel太重要了,应该说是否理解服务容器的概念是区分是否入门laravel的重要条件.因为整个框架正是在 ...

  5. C/C++、C#、JAVA(二):基本类型和转换操作

    基本类型和转换操作 数据类型 C语言中的基本类型如下. 类型 存储大小 值范围 char 1 字节 -128 到 127 或 0 到 255 unsigned char 1 字节 0 到 255 si ...

  6. 欲善事先利器-IEAD插件篇

    工欲善其事,必先利其器,好鞋踢好球是非常合乎逻辑的事情. --<长江七号> 同样的开场白,不一样的酒,不一样的故事. 上篇<欲善事先利器--系统篇>已经推荐了一些个人常用的效率 ...

  7. Proteomic Profiling of Paired Interstitial Fluids Reveals Dysregulated Pathways and Salivary NID1 as a Biomarker of Oral Cavity Squamous Cell Carcinoma (解读人:张聪敏)

    文献名:Proteomic Profiling of Paired Interstitial Fluids Reveals Dysregulated Pathways and Salivary NID ...

  8. Eclipse新建项目介绍

    最近在用Eclipse,对于一个新手来说,新建项目时出现五花八门的名字,该选择哪个进行创建呢?今天小编抱着学习的态度,顺便整理分享给大家. 选择File->New->Project...  ...

  9. hdu1213 并查集板子

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1213/ 并查集是一种支持合并与查找的数据结构,在森林中进行操作,加上路径压缩,合并和查找的时间复杂度几乎都是常数 ...

  10. [二分]codeforces 274A k-Multiple Free Set

    k-Multiple Free Set time limit per test 2 seconds memory limit per test 256 megabytes input standard ...