Already shown ?
Tim M, February 15, 2011 - 12:20 pm UTC
Did not Tom's case already show this repeated for a high number? His example brings back 72,487 rows which would require the DECODE / CASE portion of the statement to be executed at least this many times - correct?
In a previous post, Tom has shown that both DECODE and CASE will use short-circuit logic (as opposed to NVL and NVL2):
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:926029357278 (which would have had the potential for a difference in performance should either CASE or DECODE use short circuit logic and the other not)
In my opinion, one should use either CASE or DECODE based on which tends to look better for the given circumstance, which one the developer is more familiar with and your personal preference. For instance with inequality or range - I think CASE is much easier to read. Simple A or B - I tend to like DECODE.
I believe it has been shown here that performance should not be a consideration when trying to decide between CASE or DECODE.
February 15, 2011 - 12:28 pm UTC
I sort of like decode in some cases because of the way it deals with null...
decode( x, 1, 'one', 2, 'two', null, 'null' )
it makes null = null :)
I sort of like case in most cases because it is much easier to read and supports complex predicates in the expression - using or's and and's and the like.
Jignesh, February 15, 2011 - 11:59 pm UTC
Tom, Thanks a lot for the feedback.
I have tested it on a table of 2 million rows on version 10.2.0.4.0
What i am not able to understand is : while autotrace ON, the statistics are almost similar in both - CASE as well as DECODE, still difference in performance.May be this behavior of poor performance by DECODE is due to 10g which is different than that of 11g (short circuit)?
I guess the trace table presented by you in your first follow-up in this thread is generated by tkprof. Is there a way to generate it through SQL prompt?
************************************************************************************************************
SQL*Plus: Release 8.1.7.0.0 - Production on Wed Feb 16 10:32:36 2011
(c) Copyright 2000 Oracle Corporation. All rights reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> set timing on
==> First execution of CASE : 7.92 seconds
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = CASE preg_underwrite_company WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
4 AND 'ALL' = CASE preg_product_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
5 AND 'ALL' = CASE preg_state_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
6 AND 'ALL' = CASE preg_bill_type WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
7 AND 'ALL' = CASE preg_broker WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
8 AND 'ALL' = CASE DECODE(preg_inception_date, NULL, 'NEW', 'REN') WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
9 AND 'ALL' = CASE preg_payment_plan WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END ;
COUNT(1)
----------
2061577
Elapsed: 00:00:07.92
==> Second execution of CASE : 0.82 seconds
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = CASE preg_underwrite_company WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
4 AND 'ALL' = CASE preg_product_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
5 AND 'ALL' = CASE preg_state_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
6 AND 'ALL' = CASE preg_bill_type WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
7 AND 'ALL' = CASE preg_broker WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
8 AND 'ALL' = CASE DECODE(preg_inception_date, NULL, 'NEW', 'REN') WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
9 AND 'ALL' = CASE preg_payment_plan WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END ;
COUNT(1)
----------
2061577
Elapsed: 00:00:00.82
==> First execution of DECODE : 7.05 seconds
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = DECODE(preg_underwrite_company,'ALL','ALL' ,'ALL')
4 AND 'ALL' = DECODE(preg_product_code,'ALL','ALL' ,'ALL')
5 AND 'ALL' = DECODE(preg_state_code,'ALL','ALL' ,'ALL')
6 AND 'ALL' = DECODE(preg_bill_type,'ALL','ALL' ,'ALL')
7 AND 'ALL' = DECODE(preg_broker,'ALL','ALL' ,'ALL')
8 AND 'ALL' = DECODE(DECODE(preg_inception_date, NULL, 'NEW', 'REN') ,'ALL','ALL' ,'ALL')
9 AND 'ALL' = DECODE(preg_payment_plan,'ALL','ALL' ,'ALL');
COUNT(1)
----------
2061577
Elapsed: 00:00:07.05
==> Second execution of DECODE : 6.39 seconds
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = DECODE(preg_underwrite_company,'ALL','ALL' ,'ALL')
4 AND 'ALL' = DECODE(preg_product_code,'ALL','ALL' ,'ALL')
5 AND 'ALL' = DECODE(preg_state_code,'ALL','ALL' ,'ALL')
6 AND 'ALL' = DECODE(preg_bill_type,'ALL','ALL' ,'ALL')
7 AND 'ALL' = DECODE(preg_broker,'ALL','ALL' ,'ALL')
8 AND 'ALL' = DECODE(DECODE(preg_inception_date, NULL, 'NEW', 'REN') ,'ALL','ALL' ,'ALL')
9 AND 'ALL' = DECODE(preg_payment_plan,'ALL','ALL' ,'ALL');
COUNT(1)
----------
2061577
Elapsed: 00:00:06.39
**********************************************************************************************************************
SQL> set autotrace on
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = DECODE(preg_underwrite_company,'ALL','ALL' ,'ALL')
4 AND 'ALL' = DECODE(preg_product_code,'ALL','ALL' ,'ALL')
5 AND 'ALL' = DECODE(preg_state_code,'ALL','ALL' ,'ALL')
6 AND 'ALL' = DECODE(preg_bill_type,'ALL','ALL' ,'ALL')
7 AND 'ALL' = DECODE(preg_broker,'ALL','ALL' ,'ALL')
8 AND 'ALL' = DECODE(DECODE(preg_inception_date, NULL, 'NEW', 'REN') ,'ALL','ALL' ,'ALL')
9 AND 'ALL' = DECODE(preg_payment_plan,'ALL','ALL' ,'ALL');
COUNT(1)
----------
2061577
Elapsed: 00:00:06.02
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=16260 Card=1 Bytes
=30)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'POLICY_REGISTER' (TABLE) (Cost=1
6260 Card=1 Bytes=30)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
89173 consistent gets
0 physical reads
0 redo size
203 bytes sent via SQL*Net to client
255 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> SELECT COUNT(1)
2 FROM policy_register
3 WHERE 'ALL' = CASE preg_underwrite_company WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
4 AND 'ALL' = CASE preg_product_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
5 AND 'ALL' = CASE preg_state_code WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
6 AND 'ALL' = CASE preg_bill_type WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
7 AND 'ALL' = CASE preg_broker WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
8 AND 'ALL' = CASE DECODE(preg_inception_date, NULL, 'NEW', 'REN') WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END
9 AND 'ALL' = CASE preg_payment_plan WHEN 'ALL' THEN 'ALL' ELSE 'ALL' END ;
COUNT(1)
----------
2061577
Elapsed: 00:00:00.13
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=16221 Card=1 Bytes
=30)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'POLICY_REGISTER' (TABLE) (Cost=1
6221 Card=2061577 Bytes=61847310)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
89173 consistent gets
0 physical reads
0 redo size
221 bytes sent via SQL*Net to client
255 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
February 16, 2011 - 8:39 am UTC
if you would have used a more recent sqlplus, you would have seen "why" right away
If you were an optimizer and you saw:
when X then X else X end;
what might you optimizer that code into. I would optimize it into 'X'.
And if you saw
where 'x' = ... when 'x' then 'x' else 'x' end
what might you optimize that into?
[this space left intentionally blank]
ops$tkyte%ORA11GR2> set autotrace traceonly explain
ops$tkyte%ORA11GR2> select * from dual where 'x' = case dummy when 'x' then 'x' else 'x' end;
Execution Plan
----------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
ops$tkyte%ORA11GR2> select * from dual where 'x' = decode( dummy, 'x', 'x', 'x' );
Execution Plan
----------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(DECODE("DUMMY",'x','x','x')='x')
ops$tkyte%ORA11GR2>
See the predicate information - optimized away in case 1, not so in case 2.
Now - do two things
a) set up more real world examples testing actual behavior :)
b) get up to date on sqlplus - 8.1.7 sqlplus means you are missing out on lots of stuff invented this century.