好久没有写博客了,今天遇到经典案例, 经典思想碰撞。 不得不写博客纪念。 我一直认为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, 原因按照知鱼大哥这种分析方法,很快得到答案, 也能理解 各个方案的应用场景
经典SQL改写案例
最新推荐文章于 2024-07-14 19:43:26 发布