经典SQL改写案例

   好久没有写博客了,今天遇到经典案例, 经典思想碰撞。 不得不写博客纪念。   我一直认为SQL 不牛逼, 做不了好的表模型,数据模型,业务模型设计 ,  而往往好的架构设计
就体现在好的 业务数据模型中。   
 SQL:  SELECT COUNT(*)  FROM JBPM_XXXX T
  JOIN XXXX_PSED PI       ON T.VPTST = PI.ID_
 INNER JOIN CCFORM_V_RY D    ON D.CSF_ID = PI.ID_
 WHERE (T.END_ = (SELECT MAX(END_)
                    FROM JBPM_XXXX
                   WHERE VPTST = D.CSF_ID
                     AND D.CF_GDSTA IN ('K')) OR
       (T.END_ IS NULL AND T.ISOPEN_ = 1));   
很简单的SQL, 但是需要跑29分钟,结果19W     谁受得了29分钟的等待???  
执行计划”


看得到性能瓶颈吗??  如果你看不到, 那证明你还需要修炼.......
要优化这个SQL, 除了改写 别无他法.........
这个SQL知鱼 大哥也改了,改完后和我讨论,   但是他不给答案给我......      也就是因为不给答案给我 , 我才去寻找答案。   结果产生新的思路, 才有思维碰撞。 
这个也是 我尊敬知鱼大哥的, 另外我也崇拜 知鱼大哥的思路.....     这个有机会 写一遍博客专门分析知鱼大哥的思路和思维方式。  


我的思路 :
  这个SQL好怪的。。。
   T.VPTST = PI.ID_  
    D.CSF_ID = PI.ID_
  VPTST = D.CSF_ID
  迷惑性很强.......  跳过这个迷雾, 使用分析函数 计算出 最值, 然后再判断 or 
我的改写:
 select count(*) from (    
 SELECT T.VPTST, T.ISOPEN_ , T.END_, Max(case when  D.CF_GDSTA IN ('K')  then T.END_ else end ) over(partition by  VPTST) mtd 
  FROM JBPM_XXXX T
 JOIN XXXX_PSED PI ON T.VPTST = PI.ID_
 INNER JOIN CCFORM_V_RY D  ON D.CSF_ID = PI.ID_
 ) where   T.END_ =  mtd  or  (  T.END_ IS NULL AND T.ISOPEN_ = 1 );


知鱼大哥的思路:
 这个相当于标量。 关联后在用 sum( case when )  做条件统计
with v as
(SELECT VPTST, MAX(END_) max_end_
FROM JBPM_XXXX
GROUP BY VPTST)
SELECT sum(case when (T.END_ is null and T.ISOPEN_ = 1) or T.END_ = v.max_end_ then 1 else 0 end)
  FROM JBPM_XXXX T
  JOIN XXXX_PSED PI ON T.VPTST = PI.ID_
  JOIN CCFORM_V_RY D ON D.CSF_ID = PI.ID_
  LEFT JOIN v on (v.VPTST = D.CSF_ID AND D.CF_GDSTA IN ('K'))


然后知鱼大哥分析我的改写


和原始SQL对比后


红色方框的内容


你多了一个分析函数
 
这个分析函数的增加并不影响方框内的结果集
 
再看where过滤部分


很明显  
where过滤部分也是等价的过滤


分析到位,简单,精准,  我的分析远远不如......


那数据说话:   原始SQL, 和改写后的SQL 执行结果等价....


但是  知鱼大哥改写的稍快  2S, 我改写的3S, 原因按照知鱼大哥这种分析方法,很快得到答案,  也能理解 各个方案的应用场景   








  




猜你喜欢

转载自blog.csdn.net/daiqiulong2/article/details/62236172