今天同事咨询一个SQL语句,如下所示,SQL语句本身并不复杂,但是执行效率非常糟糕,糟糕到一塌糊涂(执行计划也是相当复杂)。如果查询条件中没有NOT EXISTS部分,倒是不要一秒就能查询出来。

SELECT * FROM dbo.UVW_PDATest a WITH(NOLOCK)
WHERE  
Remark='前纺' AND Operation_Name='粗纱' AND One_Status_Code='0047'  
         AND a.Createtime >='2015-9-23'
AND  NOT EXISTS
        (
          SELECT 1 FROM dbo.UVW_PDATest c WITH(NOLOCK)
          WHERE a.Task_NO =c.Task_NO AND c.One_Status_Code='0014'
        )

为什么如此简单的SQL语句,执行效率却一塌糊涂呢,因为UVW_PDATest是一个视图,而且该视图是由8个表关联组成。

SELECT ..........
From dbo.PDA_TB_Produce a With(Nolock)
  Join dbo.DctOperationList b With(Nolock)
   On a.Operation_Code=b.Operation_Code
  Join dbo.DctOneStatusList c With(Nolock)
   On a.One_Status_Code=c.One_Status_Code
  Left join dbo.DctTwoStatusList d With(Nolock)
   On c.One_Status_Code=d.One_Status_Code and a.Two_Status_Code=d.Two_Status_Code
  left Join dbo.DctMachineList e With(Nolock)
   On a.Operation_Code=e.Operation_Code and a.Machine_Code=e.Machine_Code
  left Join dbo.DctOperationList f With(Nolock)
   On a.Next_Operation_Code=f.Operation_Code
  Join dbo.DctUserList g With(Nolock)
   On a.User_ID_Operating=g.User_ID
  Join dbo.DctUserList h With(Nolock)
   On a.User_ID=h.User_ID

刚开始我想从索引上去优化,加上一两个索引后发现其实并无多大益处。为什么性能会如此糟糕呢?原因是什么呢?

大量复杂的Join

该类查询模式包含了大量连接,尤其是连接条件是不等连接,由于统计信息随着表连接的增多精度逐渐下降,这会导致低效的查询性能。解决这类情况可以通过分解查询,并将中间解决存入临时表解决。 具体参考博客:什么情况下应该分解复杂的查询来提升性能

于是我拆分上面SQL语句(如下所示),先将执行结果保存到临时表,然后关联取数,结果一秒钟的样子就执行出来了。真可谓是化繁为简。

SELECT Task_NO INTO #TMP_MID_UVW_PDATest
FROM dbo.UVW_PDATest c WITH(NOLOCK)
  WHERE One_Status_Code='0014' and Remark='前纺' AND Operation_Name='粗纱'
         
SELECT * INTO #TMP_UVW_PDATest
FROM dbo.UVW_PDATest a WITH(NOLOCK)
WHERE   Remark='前纺'
 AND Operation_Name='粗纱'
 AND One_Status_Code='0047'  
    AND Create_Date>='2015-9-23' ;
         
SELECT  * FROM #TMP_UVW_PDATest a
    WHERE NOT EXISTS(SELECT 1 FROM #TMP_MID_UVW_PDATest c WHERE a.Task_NO =c.Task_NO );
 
DROPTABLE#TMP_UVW_PDATest
DROP TABLE #TMP_MID_UVW_PDATest

第二个案例是ORACLE数据库的一个优化案例,具体SQL语句如下所示,执行时间非常长,一般都是二十多秒左右。

SELECT A.SC_NO,
   A.MRP_GROUP_CD, 
   A.DIMM_ID, 
   A.JOB_ORDER_NO, 
   DECODE(SIGN(A.DEMAND_QTY),-1,0,A.DEMAND_QTY) AS DIFF_QTY, 
   A.ASSIGNED_TYPE 
FROM 
   (
   SELECT CC.SC_NO,
      BB.MRP_GROUP_CD, 
      BB.DIMM_ID, 
      BB.JOB_ORDER_NO, 
      NVL (SUM (BB.DEMAND_QTY), 0) - NVL(SUM(REC.RECV_QTY),0) AS DEMAND_QTY, 
      CASE 
         WHEN DD.REQ_DATE<TRUNC(SYSDATE) THEN 'AH' 
         ELSE 'AS' 
      END AS ASSIGNED_TYPE 
   FROM MRP_JO_DEMAND BB,
      PO_HD CC ,
      (
      SELECT JOB_ORDER_NO,
         DIMM_ID,
         SUM(RECV_QTY) AS RECV_QTY 
      FROM MRP_AGPO_SCHD_RECV_SPECIFIC 
      GROUP BY JOB_ORDER_NO,
         DIMM_ID 
      ) 
      REC,
      MRP_JO_ASSIGN DD 
   WHERE BB.JOB_ORDER_NO=CC.PO_NO 
  AND BB.JOB_ORDER_NO=REC.JOB_ORDER_NO(+) 
  AND BB.DIMM_ID=REC.DIMM_ID(+) 
  AND BB.JOB_ORDER_NO = DD.JOB_ORDER_NO(+) 
  AND BB.DIMM_ID = DD.DIMM_ID(+) 
  AND BB.MRP_GROUP_CD=DD.MRP_GROUP_CD(+) 
  AND EXISTS 
      (
      SELECT 1 
      FROM MRP_DIMM AA 
      WHERE AA.MRP_GROUP_CD=BB.MRP_GROUP_CD 
     AND AA.DIMM_ID=BB.DIMM_ID 
     AND AA.JOB_ORDER_NO=BB.JOB_ORDER_NO 
      ) 
   GROUP BY CC.SC_NO,
      BB.MRP_GROUP_CD, 
      BB.DIMM_ID, 
      BB.JOB_ORDER_NO,
      DD.REQ_DATE
   ) 
   A, 
   INVSUBMAT.INV_MRP_JO_AVAILABLE_V B 
WHERE A.JOB_ORDER_NO = B.JOB_ORDER_NO 
AND A.MRP_GROUP_CD = B.MRP_GROUP_CD 
AND A.DIMM_ID = B.DIMM_ID 
AND NVL (A.DEMAND_QTY, 0) < NVL (B.AVAILABLE_QTY, 0) 
AND NVL (B.AVAILABLE_QTY, 0)>0 
ORDER BY A.MRP_GROUP_CD,
   A.DIMM_ID,
   A.JOB_ORDER_NO;

查看执行计划,你会发现COST主要耗费在HASH JOIN上。如下截图所示,表INV_STOCK_ASSIGN来自于视图INVSUBMAT.INV_MRP_JO_AVAILABLE_V。

将上面复杂SQL拆分后,执行只需要不到一秒解决,如下截图所示,速率提高了几十倍。优化往往有时候很复杂,有时候也很简单,就是将复杂的语句拆分成简单的SQL语句,性能的提升有时候确实令人吃惊!

CREATE GLOBAL TEMPORARY TABLE TMP_MRP_MID_DATA
( SC_NO           VARCHAR2(20) ,
 MRP_GROUP_CD    VARCHAR2(10) ,
  DIMM_ID          NUMBER,
  JOB_ORDER_NO    VARCHAR2(20) ,
  DEMAND_QTY      NUMBER       ,
  DIFF_QTY        NUMBER       ,
  ASSIGNED_TYPE   VARCHAR(2)
) ON COMMIT PRESERVE ROWS;
 
 
INSERT INTO TMP_MRP_MID_DATA
SELECT A.SC_NO,
   A.MRP_GROUP_CD, 
   A.DIMM_ID, 
   A.JOB_ORDER_NO, 
   A.DEMAND_QTY,
   DECODE(SIGN(A.DEMAND_QTY),-1,0,A.DEMAND_QTY) AS DIFF_QTY, 
   A.ASSIGNED_TYPE 
FROM 
   (
   SELECT CC.SC_NO,
      BB.MRP_GROUP_CD, 
      BB.DIMM_ID, 
      BB.JOB_ORDER_NO, 
      NVL (SUM (BB.DEMAND_QTY), 0) - NVL(SUM(REC.RECV_QTY),0) AS DEMAND_QTY, 
      CASE 
         WHEN DD.REQ_DATE<TRUNC(SYSDATE) THEN 'AH' 
         ELSE 'AS' 
      END AS ASSIGNED_TYPE 
   FROM MRP_JO_DEMAND BB
      INNER JOIN  PO_HD CC ON BB.JOB_ORDER_NO=CC.PO_NO
        LEFT JOIN  (
      SELECT JOB_ORDER_NO,
         DIMM_ID,
         SUM(RECV_QTY) AS RECV_QTY 
      FROM MRP_AGPO_SCHD_RECV_SPECIFIC 
      GROUP BY JOB_ORDER_NO,
         DIMM_ID 
      ) 
   REC ON  BB.JOB_ORDER_NO=REC.JOB_ORDER_NO AND BB.DIMM_ID=REC.DIMM_ID
      LEFT JOIN  MRP_JO_ASSIGN DD ON BB.JOB_ORDER_NO = DD.JOB_ORDER_NO   AND BB.DIMM_ID = DD.DIMM_ID  AND BB.MRP_GROUP_CD=DD.MRP_GROUP_CD
      INNER JOIN MRP_DIMM AA  ON AA.MRP_GROUP_CD=BB.MRP_GROUP_CD   AND AA.DIMM_ID=BB.DIMM_ID    AND AA.JOB_ORDER_NO=BB.JOB_ORDER_NO  
   GROUP BY CC.SC_NO,
      BB.MRP_GROUP_CD, 
      BB.DIMM_ID, 
      BB.JOB_ORDER_NO,
      DD.REQ_DATE
   ) 
   A;
   COMMIT;
 
SELECT A.* FROM
TMP_MRP_MID_DATA A INNER JOIN
   INVSUBMAT.INV_MRP_JO_AVAILABLE_V B  ON A.JOB_ORDER_NO = B.JOB_ORDER_NO 
          AND A.MRP_GROUP_CD = B.MRP_GROUP_CD 
            AND A.DIMM_ID = B.DIMM_ID 
WHERE
NVL (A.DEMAND_QTY, 0) < NVL (B.AVAILABLE_QTY, 0) 
AND NVL (B.AVAILABLE_QTY, 0)>0 
ORDER BY A.MRP_GROUP_CD,
   A.DIMM_ID,
   A.JOB_ORDER_NO;

小结:

1:越是复杂的SQL语句,优化器越是容易选择一个糟糕的执行计划(优 化器之所以难以选定最优的执行计划,是因为优化器要平衡选定最优执行路径的代价,不能一味为了选择最优执行计划,而将复杂SQL的所有执行路径都计算对比 一遍,往往只能有选择性的选取一些执行路径计算对比,否则开销太大。而越是复杂的SQL,可选择的执行路径就是越多。

说得有点绕口,还是打个比方,比如你从广州到北京,如果就 只有飞机(直飞),火车(直达)、汽车(直达)三种选择,那么想必你能很快给出一个最优的路线(例如,最快的是飞机、最省钱的是火车),但是如果飞机、火 车、汽车都不能直达:假如火车票没有了直达,你必须中途转几次、飞机票也没有直达了,你需要转机,那么此时选择性复杂的情况,你就必须花费不少时间才能制 定一个最优的计划了。 如果在复杂一点的情况,你从中国去美国,是不是有N种路径? 如果全部计算对比一遍各种可能的路径,估计你小脑袋不够用………………

2:执行计划是可以被重用的,越简单的SQL语句被重用的可能性越高。而复杂的SQL语句只要有一个字符发生变化就必须重新解析,然后再把这一大堆垃圾塞在内存里。可想而知,数据库的效率会何等低下。

3:如果SQL语句过分复杂,要么是业务有问题,要么是模型设计不当。可以说复杂的SQL反映出系统设计方面有不少问题和缺陷。

化繁为简——分解复杂的SQL语句相关推荐

  1. SQL语句优化之降龙十八掌

    sql 语句优化 一前言  客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急剧下降,小型机idle所剩无几,应用服务器断连.超时,严重影响业 ...

  2. 基于索引的SQL语句优化之降龙十八掌

    一篇挺不错的关于SQL语句优化的文章,因不知原始出处,故未作引用说明! 1 前言       客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能 ...

  3. 基于索引的SQL语句优化之降龙十八掌(转载)!

    一篇挺不错的关于SQL语句优化的文章,因不知原始出处,故未作引用说明,如有侵权,请联系本人! 1 前言       客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不 ...

  4. 关于索引的sql语句优化之降龙十八掌

    1 前言       客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急剧下降,小型机idle所剩无几,应用服务器断连.超时,严重影响业务的正 ...

  5. 快速提升性能的SQL语句,建议收藏

    来源:cnblogs.com/SimpleWu/p/9929043.html 本文会提到 52 条 SQL 语句性能优化策略. 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 WHERE 及 O ...

  6. SQL语句书可以提高执行效率的5种需要注意的书写方法

    之前收集的一些资料仅供参考, 不一定完全正确... 有错误望指正 1.操作符号: NOT IN操作符 此操作是强列推荐不使用的,因为它不能应用表的索引.推荐方案:用NOT EXISTS 或(外连接+判 ...

  7. oracle 哦【的【,清晰讲解SQL语句中的外连接,通用于Mysql和Oracle,全是干货哦

    清晰讲解SQL语句中的外连接,通用于Mysql和Oracle,全是干货哦 直入主题: 我们做一个操作,将员工SCOTT的部门去掉,再次通过内连接查看数据,看看会产生什么现象? 使用内连接,查询数据 问 ...

  8. 爆肝,52条SQL语句,性能优化,干货必收藏 !

    作者 | SimpleWu 来源 | cnblogs.com/SimpleWu/p/9929043.html SQL语句性能优化 1, 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 ...

  9. 从痴迷数据库SQL语句逐渐走进面向对象化(系统的核心以处理对象为主、淡化数据库概念)...

    几年前写信息管理系统都要设计很多很多表,每个表都是自己建立的,然后喜欢用高   性能.高超的SQL语句搞定很多复杂的商业逻辑问题,那SQL语句又长又复杂,一般人   还读不懂,但是代码很少.性能很高, ...

最新文章

  1. 比Navicat还要好用的通用数据库管理工具,功能强大还免费
  2. 角色权限(Role)和系统权限(System)的几个澄清实验
  3. zabbix监控haproxy
  4. freeRtos学习笔记 (6)软件定时器
  5. wpf click事件在触摸屏上点击第一次没反应_你的PLC和你的触摸屏为什么总是通讯不上?...
  6. Android 系统(64)---Android中m、mm、mmm、mma、mmma的区别
  7. 设计模式学习-每日一记(1.简单工厂模式)
  8. android ffmpeg 优点_在Android中使用FFmpeg(android studio环境)
  9. 【LeetCode】231. Power of Two
  10. 无废话ExtJs 入门教程八[脚本调试Firefox:firebug]
  11. 无可用源 没有为任何调用堆栈加载任何符号_看完这篇后,别再说你不懂JVM类加载机制了~...
  12. 哈夫曼树及哈夫曼编码例题
  13. 干货!一份详实的 Scrapy 爬虫教程,值得收藏!
  14. 易班登陆接口接入实例
  15. 三大控制结构 js函数定义
  16. GOBY--一款攻击面测绘工具的使用
  17. Linux下PHP下载安装
  18. 必须要知道的多媒体知识-音视频编解码-h265、h264-直播-点播
  19. 使用递归函数输出斐波那契数列
  20. (原创)LEON3入门教程(一):什么是LEON3?需要哪些开发工具和软件?

热门文章

  1. 基于纹理的复杂环境下道路消失点检测算法
  2. 快速缩小GIF图片文件的两种方式
  3. java 编写线程公共类_Java实现线程间通信方式
  4. 机器学习算法基础之使用python代码
  5. windows密钥查看器ProduKey1.82汉化
  6. 打开*.acb格式音频文件
  7. Javaweb——水果系统基础版
  8. 梅科尔工作室——鸿蒙设备开发实战004:内核开发
  9. 定制材料 单壁碳纳米管包裹Cu原子链/碳纳米管包裹的硅纳米线复合结构/氮掺杂碳纳米管包裹钴
  10. 华为认证有什么地方可以学习考取?