暂无图片
SQL 优化
我来答
分享
周伟
2022-11-30
SQL 优化

有没有哪位大师想练手的,看看以下这个SQL有没有什么优化思路:

背景: 该SQL每天执行一次,其中 t 表非常庞大,有75G,不考虑碎片整理,不考虑并行的情况,只存储考虑SQL优化的情况。这个SQL在SSD盘上执行需要12分钟。


SELECT CASE
                WHEN
                      TRUNC(ADD_MONTHS(t.CLOSEDDATE, 2), 'MM') - 1 > TRUNC(CURRENT_DATE, 'DD') - 1
                 THEN
                       t.CLOSEDDATE + TO_CHAR(TRUNC(CURRENT_DATE, 'DD') - 1, 'DD')
                  ELSE
                       TRUNC(ADD_MONTHS(t.CLOSEDDATE, 2), 'MM') - 1
                  END AS STATDATE,
                  COMCODE,
                  CHANNELSUBTYPECODE,
                  RISKCODE,
                  PERAGENTTYPE,
                 OUTERDATASRCCODE,
                NVL(ROLL2OUTSTANDINGNUMBER, '0') + NVL(ROLL2ENDNOTPAYNUMBER, '0') as                   ROLL2OUTSTANDINGNUMBER
   from WEB_CP_RISK_ALL t
Where CASE
              WHEN
                   TRUNC(ADD_MONTHS(t.CLOSEDDATE, 2), 'MM') - 1 > TRUNC(CURRENT_DATE, 'DD') - 1
               THEN
                   t.CLOSEDDATE + TO_CHAR(TRUNC(CURRENT_DATE, 'DD') - 1, 'DD')
                ELSE
                   TRUNC(ADD_MONTHS(t.CLOSEDDATE, 2), 'MM') - 1
                END < TRUNC(CURRENT_DATE, 'DD');

这个SQL的难点在于current_date, 也就是每天执行的时候,都需要将整个表的closedate与当天的时间进行计算对比,因此索引或者函数索引的方式就不太可行。其它能想到的就是物化视图,每天全量刷新一次,然后和这个SQL的执行时间错开。但实际上跟这个SQL一起执行效果上也没啥区别。

请教各位专家,有没有啥好的改写方式。

我来答
添加附件
收藏
分享
问题补充
3条回答
默认
最新
Thomas

你这个逻辑太复杂,我反复拆解,大致得出结论:假设closeddate必然小于current_date,且closeddate一旦录入了不会变化。 那么只要closeddate<trunc(current_date,'MM'),就必然符合where条件。比如现在是2022-12-02,那么只要closeddate是2022年12月份之前的,都会被where 选出来。而select 里的计算,又分两种情况处理:情况A:如果closeddate为上月,则statdate=closeddate+(current_date的日期部分减1); 情况B,如果closeddate为上月之前,那么statdate=closeddate所在月的后一个月的最后一天的零点。既然这样,可考虑在表里加两个字段,YM_CLOSEDDATE CHAR(6),存CLOSEDDATE的YYYYMM部分(该字段上要建索引),以及FIXED_STATDATE,存情况B下相对固定的STATDATE。表DML时,可用触发器方式给YM_CLOSEDDATE赋值,比如:new.ym_closed_date=to_char(:new.closeddate,'YYYYMM')。每晚搞个定时任务,运行update 表 set fixed_statdate=TRUNC(ADD_MONTHS(t.CLOSEDDATE, 2), 'MM') - 1 where fixed_statdate is null and ym_closeddate<to_char(add_month(current_date,-1),'YYYYMM'); 以后的SQL改为:

select fixed_statdate as statdate,... from 表 where ym_closeddate<to_char(add_month(current_date,-1),'YYYYMM')

union all

select closed_date+TO_CHAR(TRUNC(CURRENT_DATE, 'DD') - 1, 'DD') as statdate, ... from 表 where ym_closeddate=to_char(add_month(current_date,-1),'YYYYMM');

暂无图片 评论
暂无图片 有用 0
暂无图片
周伟
题主
2022-12-05
感谢专家耐心解答,大致意思和你的思路差不多,这个SQL的SELECT处理部分和where的过滤条件部分实际上是一样的逻辑。我们也想过就过滤条件或者select部分弄个物化视图然后每天晚上刷新,减少白天业务的处理时间,思路和你的触发器和fix字段办法类似。他们这个需求麻烦就麻烦在每天都需要对整个表的所有记录都进行一次和current_date的比较计算,所以也避免不了全扫的麻烦了。
yBmZlQzJ

坐等大佬解答,学习学习。

暂无图片 评论
暂无图片 有用 0
游湖

这sql看着头疼

暂无图片 评论
暂无图片 有用 1
回答交流
提交
问题信息
请登录之后查看
邀请回答
暂无人订阅该标签,敬请期待~~
暂无图片墨值悬赏