使用反CASE思想,改写SQL

这篇博客探讨了在SQL优化中运用反CASE思想来改写查询,以解决ORACLE优化器选择全表扫描的问题。文章通过建表、填充数据、加索引等步骤,展示了如何针对特定情况改写SQL,从而提高查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面是自己写的一个小样,只是说说原理。

真实SQL比这个要复杂些,但是处理方法相同。

1建表

SQL> create table test_case_anti
  2  as
  3  select   sysdate+1/24/60  d1, sysdate-356+1/24/60  d2, 1 d3
  4    from  dual
  5   where 1=2 ;

Table created.


2 插入一百万行数据

SQL>  begin
  2     for i in 1..1000000
  3            loop
  4     insert into test_case_anti 
  select  sysdate+i/24/60 ,sysdate-356+i/24/60,i   from dual ;
  5    6     if mod(i,1000)=0 then commit ;end if ; 
  7     
  8     end loop ;
  9     
 10   end ;
 11  /

PL/SQL procedure successfully completed.

SQL> commit ;

Commit complete.

3  加索引 

SQL> create index idx_dao_1 on TEST_CASE_ANTI(d1) ; 

Index created.

SQL> create index idx_dao_2 on TEST_CASE_ANTI(d2) ; 

Index created.

4  原始语句及执行计划

SQL>  select  *
  2  from test_case_anti x
  3  where (case when  d3=2  then x.d1 else d2 end )= trunc(sysdate+1) ;


no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 875620970

------------------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                |    40 |  1240 |  1036   (5)| 00:00:13 |
|* <span style="color:#FF0000;"> 1 |  TABLE ACCESS FULL| TEST_CASE_ANTI |    40 |  1240 |  1036   (5)| 00:00:13 |</span>
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(CASE "D3" WHEN 2 THEN "X"."D1" ELSE "D2" END
              =TRUNC(SYSDATE@!+1))

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          5  recursive calls
          2  db block gets
       3763  consistent gets
          0  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        512  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

由于在WHERE子句中使用了CASE ,使过滤谓词使用的列出现了不确定性。

ORACLE优化器无法判断应该使用那个索引,所以给出全表的扫描执行计划


5 对于此种情况,需要进行SQL改写

> SQL> select  *
from test_case_anti x
  2    3  where d3=2 
and d1=trunc(sysdate+1)
union all 
select  *
from test_case_anti x
where d3!=2 
and d2=trunc(sysdate+1);
  4    5    6    7    8    9  
no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3938109978

-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                |   121 |  3751 |     8  (50)| 00:00:01 |
|   1 |  UNION-ALL                   |                |       |       |            |          |
|*  2 |   TABLE ACCESS BY INDEX ROWID| TEST_CASE_ANTI |    81 |  2511 |     4   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IDX_DAO_1      |    40 |       |     3   (0)| 00:00:01 |
|*  4 |   TABLE ACCESS BY INDEX ROWID| TEST_CASE_ANTI |    40 |  1240 |     4   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN          | IDX_DAO_2      |    40 |       |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("D3"=2)
   3 - access("D1"=TRUNC(SYSDATE@!+1))
   4 - filter("D3"<>2)
   5 - access("D2"=TRUNC(SYSDATE@!+1))

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          9  recursive calls
          2  db block gets
        238  consistent gets
          7  physical reads
          0  redo size
        458  bytes sent via SQL*Net to client
        512  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed


改写后拆开WHERE字句中的CASE表达式,虽然执行计划变得稍微复杂,但是COST大幅降低。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值