标量子查询SQL改写一则(包括WITH的改写)

原SQL,执行了6.8小时后报ora-01555错误无法完成:

select t.operid || '|' || sum(score) || '|' ||
       nvl((select sum(score)
             from cs_score_operdayscore t1
            where t1.operid = t.operid
              and t1.scoredate > to_date(20120801, 'yyyymmdd')
              and t1.scoreid in
                  (select dictname
                     from dict_item
                    where groupid in ('SHOPSCOREEXCHG',
                                      'SCOREEXCHGFEE',
                                      'SCOREEXCHGSELFBUSI',
                                      'SCOREEXCHGSUPPERPRESENT',
                                      'SCOREEXCHGXHNEWS',
                                      'SCOREEXCHGMIFI',
                                      'SCOREEXCHGTEMPPRESENT'))),
           0) || '|' ||
       nvl((select sum(score)
             from cs_score_operdayscore t1
            where t1.operid = t.operid
              and t1.scoredate > to_date(20120801, 'yyyymmdd')
              and t1.scoreid in
                  (select dictname
                     from dict_item
                    where groupid = 'NEWBUSISCORE')),
           0)
  from cs_score_operdayscore t
 where scoredate > to_date(20120801, 'yyyymmdd')
 group by operid;

sql monitor采集的执行计划如下:


问题:

 cs_score_operdayscore是一张大表(1亿条以上),从谓词条件看,将近3年的数据基本上不会过滤掉多少记录,在如此大的一张表上,使用标量子查询(即select 的column列表中使用了select子句),性能是非常非常差的,需要通过外关联的方式进行改写才能提高性能。

而同一张表在标量子查询里面又被用到,这种情况可以使用WITH来进行改写;因为这个SQL是大表做统计分析,一般是DW系统或是OLTP系统晚上操作,为了缩短响应时间和资源消耗,一般建议增加并行操作,最终改写后的SQL如下:

with main as 
(select operid,score,scoreid  from cs_score_operdayscore where scoredate > to_date(20120801, 'yyyymmdd') )
select /*+ parallel(8) */
  t.operid || '|' || sum_t || '|' ||nvl(sum_t1,0) || '|' ||nvl(sum_t2,0) from 
(select operid,sum(score) sum_t  from main group by operid) t,
(select operid,sum(score) sum_t1 from main where scoreid in
                  (select /*+ full(dict_item) */dictname
                     from dict_item
                    where groupid in ('SHOPSCOREEXCHG',
                                      'SCOREEXCHGFEE',
                                      'SCOREEXCHGSELFBUSI',
                                      'SCOREEXCHGSUPPERPRESENT',
                                      'SCOREEXCHGXHNEWS',
                                      'SCOREEXCHGMIFI',
                                      'SCOREEXCHGTEMPPRESENT')
                   )group by operid
) t1,
(select operid,sum(score) sum_t2 from main where scoreid in
                  (select /*+ full(dict_item) */dictname
                     from dict_item
                    where groupid = 'NEWBUSISCORE')
                   group by operid
) t2
where t.operid=t1.operid(+) and
      t.operid=t2.operid(+) ; 

这个SQL最终的执行时间是4分钟(并行度设置为8),下面是部分执行计划的内容:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以将标量子查询嵌套在 SELECT 语句中作为一个列,然后在外部 SELECT 语句中选择该列。例如: ``` SELECT column1, (SELECT COUNT(*) FROM my_table WHERE column2 = 'my_value') as scalar_subquery FROM my_table WHERE column1 = 'another_value'; ``` 在上面的示例中,标量子查询 `(SELECT COUNT(*) FROM my_table WHERE column2 = 'my_value')` 返回一个值,该值作为一个名为 `scalar_subquery` 的列包含在结果集中。 如果你想要抓取标量子查询SQL 语句,可以使用以下方法: 1. 将标量子查询作为一个子查询,并将其结果集保存到一个临时表中,然后在外部查询中使用该临时表。例如: ``` CREATE TABLE temp_table AS SELECT COUNT(*) as count_value FROM my_table WHERE column2 = 'my_value'; SELECT column1, count_value FROM my_table, temp_table WHERE column1 = 'another_value'; ``` 在上面的示例中,第一个 SELECT 语句将标量子查询的结果集保存到一个名为 `temp_table` 的临时表中,然后在第二个 SELECT 语句中使用该临时表。 2. 使用变量来存储标量子查询的结果,并将该变量作为参数传递给外部查询。例如: ``` DECLARE @count_value INT; SELECT @count_value = (SELECT COUNT(*) FROM my_table WHERE column2 = 'my_value'); SELECT column1, @count_value FROM my_table WHERE column1 = 'another_value'; ``` 在上面的示例中,第一个 SELECT 语句将标量子查询的结果保存到一个名为 `@count_value` 的变量中,然后在第二个 SELECT 语句中使用该变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值