工作中我们经常用到多个left join去关联其他表查询结果,但是随着数据量的增加,一个表的数据达到百万级别后,这种普通的left join查询将非常的耗时。

举个例子:

    现在porder表有 1000W数据,其他关联的表数据都很少,因为条件的限制必须要关联3个表,正常的逻辑就是这样写,但是我们在数据库执行的时候会发现这样的SQL非常耗时,而且此时才 limit 800  这样的SQL怎么能让用户受得了呢?

select p.*,b.supplier,t.type,c.org   from porder p 
        left JOIN brand b on p.supplier = b.supplier_id and b.mark = 0
        left JOIN purchase c on p.org = c.id and c.mark = 0
        left JOIN type t on c.category = t.type_id and t.mark = 0 
        WHERE p.nark = 0 ORDER BY p.id desc limit 800,500;

    通过查询SQL优化方面的知识,发现一种比较好的优化方案:

select p.*,b.supplier,t.type,c.org from
        (select po.id from porder po where po.mark = 0 order by po.id desc limit 800000,500) a
        inner join porder p on a.id = p.id and p.mark = 0
        left JOIN brand b on p.supplier = b.supplier_id and b.mark = 0
        left JOIN purchase c on p.org = c.id and c.mark = 0
        left JOIN type t on c.category = t.type_id and t.mark = 0;

    我们可以先将数据量最大表的满足条件的ID查询出来,创建临时表,再用这个临时表去关联这个表本身以及其他表。limit80W 也就1S时间。

SQL分析:

   我们可以使用 explain 查看上面2种SQL的执行计划。第一种SQL的执行计划中通过 row 和extra 都可以看出非常差,row几乎为全部扫描。

   优化后的SQL通过 row 和extra 都可以看出都是很好的状态,row的数据是第一种的 1%。相当于提升了 100倍。

   执行计划中的id列的数值越大,执行权就越高。id列的值相等的,就从上之下依次执行。明白了这一点,我们就可以再分析SQL了。

   数据库先执行了 select po.id from porder po where po.mark = 0 order by po.id desc limit 800000,500 这段SQL,将查询出的有效id(满足条件的id)放在了临时表a中,然后表a再与其他的表匹配查询。

  (注:优先执行的SQL不参与后面的表匹配。这里要理解,不然单独看执行计划,你会纳闷为何row列上a表中数值小,而id列为2的表(po) row列的数值也很大。

          你也可以拆分SQL。优先执行的SQL单独拿出来执行,将查询到的结果当作查询条件,传给普通的 left join 中的where条件里面,即 in(), in的里面不要写SQL查询,必须是明确的数值!)

PS:我只是提供方法,具体的原理,大家可以上网查一查。数据库有一种叫驱动表的概念,大家可以了解下。或许对于理解这种方法更方便!

  注:这个优化后的SQL在执行 limit1000000,**  的时候效率也就下降了,大概4S钟以上。所以这个SQL也是有极限的,对于分页查询等等,如果数据量超过100W 要注意!

希望有大神,能在SQL上能有更高的突破,有方法的,希望大家一起分享,一起学习。谢谢~

  补:为了应对超过百万级别的查询或者导出,SQL优化暂时没有好的办法,但是我们可以在传参上做文章。

比如分页查询时,每页展示20条数据,首页查询时,我们可以得到首页最后一条数据的ID (起名:lastId)(按ID排序,降序),当点击第2页时,我们可以将 lastId 作为参数传入分页查询的SQL中。这样分页时就加上了一个条件,就是 ID<lastId (按ID排序,降序)。

limit也可以优化成  limit 20, 这样优化后,因为limit 不再是 limit xxx,20 ,这样数据库在扫描满足条件的数据时,就会从此ID往后扫描,且扫描到满足条件的20条后,就不会再多扫描,大大减少了扫描的数据量,自然也就提升了效率。

参考:https://www.cnblogs.com/tianzong/p/10552182.html

MySQL-数据库多表关联查询太慢,如何进行SQL语句优化的更多相关文章

  1. 项目总结04:SQL批量导入数据:将具有多表关联的Excel数据,通过sql语句脚本的形式,导入到数据库

    将具有多表关联的Excel数据,通过sql语句脚本的形式,导入到数据库 写在前面:本文用的语言是java:数据库是MySql: 需求:在实际项目中,经常会被客户要求,做批量导入数据:一般的简单的单表数 ...

  2. Python操作Mysql数据库——多表组合查询

    前面我们介绍了单张表的查询,包括模糊查询.分组.排序.各种筛选条件等等操作,在实际应用中,查询的数据往往不止局限在一张表里,通常需要多张表在一起进行组合查询,今天我们将会对Mysql当中的多张有关联的 ...

  3. ORACLE数据库多表关联查询效率问题解决方案

    最近在做项目中遇到多表关联查询排序的效率问题(5张以上40W+数据的表),查询一次大概要20多秒,经过一番苦思冥想,处理方案如下: 1.软件设计初期,需要一对一关联的表应该设计在一张大表里,这样虽然字 ...

  4. mysql三张表关联查询

    三张表,需要得到的数据是标红色部分的.sql如下: select a.uid,a.uname,a.upsw,a.urealname,a.utel,a.uremark, b.rid,b.rname,b. ...

  5. MySql数据库转设计文档(mysql-font工具和sql语句导出)

    一.工具导出 1.使用的是MySQL-Front工具,这个工具使用非常方便,尤其是导出数据的时候,几百万的数据一两分钟就导完了,推荐使用. MySQL-Front下载(只有3.93M):http:// ...

  6. mysql数据库技术1——基本的增删查改的sql语句

    1.数据库语言的分类 DDL:数据库定义语言 data Definition language 用于创建.修改.和删除数据库内的数据结构,如: 1:创建和删除数据库(CREATE DATABASE | ...

  7. MySQL在大数据、高并发场景下的SQL语句优化和"最佳实践"

    本文主要针对中小型应用或网站,重点探讨日常程序开发中SQL语句的优化问题,所谓“大数据”.“高并发”仅针对中小型应用而言,专业的数据库运维大神请无视.以下实践为个人在实际开发工作中,针对相对“大数据” ...

  8. MySQL数据库--创建表,查询

    MySQL创建表: 表(一)Student (学生表): CREATE TABLE `Student` ( `sno` ) DEFAULT NULL, `sname` ) DEFAULT NULL, ...

  9. 关于MySql数据库设计表与查询耗时分析

    本地建一张表persons,使用脚本插入了1000万条数据 下面比较几种查询方法的耗时(查询9000000到9000005这中间5条数据) 查询结果: 1: SELECT * FROM test.pe ...

随机推荐

  1. OO第四单元作业总结及课程总结

    一.本单元作业架构设计 1.第一次作业 本单元首次接触到UML以及相关概念,在面对第一次作业时首先花了很大功夫去阅读官方接口中各种UmlElement的代码,才理解了输入的模型元素中各属性的含义.总的 ...

  2. Asp.net Core使用EFCore+Linq进行操作

    注:EFCore和EF有区别,在core中写的也有一点区别,每个人写法不同仅供参考写的比较细致耐性一点看完会有收获的 首先加上必要的引用 using Microsoft.EntityFramework ...

  3. spring cloud zuul的回退

    当我们使用 @EnableZuulProxy 注解来开启zuul的路由时,默认在@EnableZuulProxy注解上就包含了@EnableCircuitBreaker注解,即开启了断路器功能.那么在 ...

  4. Noip模拟61 2021.9.25

    T1 交通 考场上想了一个$NPC$.应该吧,是要求出图里面的所有可行的不重复欧拉路 无数种做法都无法解出,时间也都耗在这个上面的,于是就考的挺惨的 以后要是觉得当前思路不可做,就试着换一换思路,千万 ...

  5. 使用google zxing生成二维码图片

    生成二维码工具类: 1 import java.awt.geom.AffineTransform; 2 import java.awt.image.AffineTransformOp; 3 impor ...

  6. $.ajax、$.get和$.post方法成功,完成请求,错误或失败的回调

    一.$.get和$.post的不同    1.get通过url提交的,post是通过http消息实体提交的    2.get提交大小限制为2kb,post不限制    3.get提交会被缓存下来,有安 ...

  7. Java项目中集成钉钉机器人推送消息提醒

    前言: 项目中有一个需求,当有新订单产生的时候,希望能够及时通知到业务相关人员进行处理,整体考虑了一下,选用了钉钉机器人提醒功能(公司内部主要也是使用钉钉进行通讯). 操作: 主要分为两部分进行处理: ...

  8. css 马赛克悬停效果

    css 马赛克悬停效果 <!DOCTYPE html> <html lang="en"> <head> <meta charset=

  9. Part 19 AngularJS Services

    What is a service in AngularJSBefore we talk about what a service is in Angular. Let's talk about a ...

  10. 跟着老猫来搞GO-容器(1)

    前期回顾 前面的一章主要和大家分享了GO语言的函数的定义,以及GO语言中的指针的简单用法,那么本章,老猫就和大家一起来学习一下GO语言中的容器. 数组 数组的定义 说到容器,大家有编程经验的肯定第一个 ...