Skip to content

Commit 13322b7

Browse files
authored
expression stats example (#169)
1 parent 778f3c7 commit 13322b7

File tree

3 files changed

+224
-0
lines changed

3 files changed

+224
-0
lines changed

optimizer/expression_stats/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Small demo to show how expression statistics can improve cardinality estimates
2+
3+
# Disclaimer
4+
5+
<br/>-- These scripts are provided for educational purposes only.
6+
<br/>-- They are NOT supported by Oracle World Wide Technical Support.
7+
<br/>-- The scripts have been tested and they appear to work as intended.
8+
<br/>-- You should always run scripts on a test instance.
9+
10+
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
2+
Table created.
3+
4+
5+
COUNT(*)
6+
----------
7+
1773
8+
9+
10+
PL/SQL procedure successfully completed.
11+
12+
13+
COUNT(*)
14+
----------
15+
1773
16+
17+
18+
PLAN_TABLE_OUTPUT
19+
----------------------------------------------------------------------------------------------------
20+
SQL_ID 8caz15dwj8w8k, child number 0
21+
-------------------------------------
22+
SELECT /* MYQUERY */ COUNT(*) FROM t WHERE ( "DELIVERY_DATE" >=
23+
trunc(sysdate@!, 'fmyear') AND ( coalesce("CONTROL_FLAG", 1) = 1
24+
OR coalesce("CONTROL_FLAG", 1) = 3 ) AND (
25+
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1' OR
26+
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' ) AND
27+
"DELIVERY_DATE" <= trunc(sysdate@! - 1) )
28+
29+
Plan hash value: 1010173228
30+
31+
32+
PLAN_TABLE_OUTPUT
33+
----------------------------------------------------------------------------------------------------
34+
----------------------------------------------------------------------------
35+
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
36+
----------------------------------------------------------------------------
37+
| 0 | SELECT STATEMENT | | | | 9 (100)| |
38+
| 1 | SORT AGGREGATE | | 1 | 15 | | |
39+
|* 2 | FILTER | | | | | |
40+
|* 3 | TABLE ACCESS FULL| T | 2 | 30 | 9 (0)| 00:00:01 |
41+
----------------------------------------------------------------------------
42+
43+
Predicate Information (identified by operation id):
44+
---------------------------------------------------
45+
46+
PLAN_TABLE_OUTPUT
47+
----------------------------------------------------------------------------------------------------
48+
49+
2 - filter(TRUNC(SYSDATE@!-1)>=TRUNC(SYSDATE@!,'fmyear'))
50+
3 - filter(((COALESCE("CONTROL_FLAG",1)=1 OR
51+
COALESCE("CONTROL_FLAG",1)=3) AND "DELIVERY_DATE"<=TRUNC(SYSDATE@!-1)
52+
AND (COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')='1' OR
53+
COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')='3') AND
54+
"DELIVERY_DATE">=TRUNC(SYSDATE@!,'fmyear')))
55+
56+
57+
30 rows selected.
58+
59+
60+
TABLE_NAME OWNER EXPRESSION_TEXT
61+
---------------------------------------- ---------------------------------------- ----------------------------------------------------------------------------------------------------
62+
T ADHOC COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')
63+
T ADHOC "DELIVERY_DATE"
64+
T ADHOC COALESCE("CONTROL_FLAG",1)
65+
66+
67+
DBMS_STATS.CREATE_EXTENDED_STATS(USER,'T',Q'[(COALESCE("CONTROL_FLAG",1))]')
68+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
69+
SYS_STUARLGZBSAG4YYL$Q$14300KT
70+
71+
72+
DBMS_STATS.CREATE_EXTENDED_STATS(USER,'T',Q'[(COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]')
73+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
74+
SYS_STU2K568KT2T5R6S37VQUN63#V
75+
76+
77+
PL/SQL procedure successfully completed.
78+
79+
80+
COUNT(*)
81+
----------
82+
1773
83+
84+
85+
PLAN_TABLE_OUTPUT
86+
----------------------------------------------------------------------------------------------------
87+
SQL_ID 8caz15dwj8w8k, child number 0
88+
-------------------------------------
89+
SELECT /* MYQUERY */ COUNT(*) FROM t WHERE ( "DELIVERY_DATE" >=
90+
trunc(sysdate@!, 'fmyear') AND ( coalesce("CONTROL_FLAG", 1) = 1
91+
OR coalesce("CONTROL_FLAG", 1) = 3 ) AND (
92+
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1' OR
93+
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' ) AND
94+
"DELIVERY_DATE" <= trunc(sysdate@! - 1) )
95+
96+
Plan hash value: 1010173228
97+
98+
99+
PLAN_TABLE_OUTPUT
100+
----------------------------------------------------------------------------------------------------
101+
----------------------------------------------------------------------------
102+
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
103+
----------------------------------------------------------------------------
104+
| 0 | SELECT STATEMENT | | | | 10 (100)| |
105+
| 1 | SORT AGGREGATE | | 1 | 13 | | |
106+
|* 2 | FILTER | | | | | |
107+
|* 3 | TABLE ACCESS FULL| T | 1363 | 17719 | 10 (10)| 00:00:01 |
108+
----------------------------------------------------------------------------
109+
110+
Predicate Information (identified by operation id):
111+
---------------------------------------------------
112+
113+
PLAN_TABLE_OUTPUT
114+
----------------------------------------------------------------------------------------------------
115+
116+
2 - filter(TRUNC(SYSDATE@!-1)>=TRUNC(SYSDATE@!,'fmyear'))
117+
3 - filter(("DELIVERY_DATE"<=TRUNC(SYSDATE@!-1) AND
118+
COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1') AND
119+
"DELIVERY_DATE">=TRUNC(SYSDATE@!,'fmyear') AND
120+
COALESCE("CONTROL_FLAG",1)))
121+
122+
123+
29 rows selected.
124+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
spool expression
2+
--
3+
-- Demonstrates the usefulness of expression statistics
4+
-- Creates a table "T" - and note that session requires
5+
-- read access to V$SESSION
6+
--
7+
set linesize 250
8+
set trims on
9+
set tab off
10+
column plan_table_output format a100
11+
column expression_text format a100
12+
column table_name format a40
13+
column owner format a40
14+
15+
var sqlid varchar2(20)
16+
17+
create table t as
18+
select sysdate-50+rownum/100 delivery_date,1 control_flag,
19+
rownum account_id
20+
from dual connect by rownum<=10000;
21+
22+
SELECT /* MYQUERY */ COUNT(*)
23+
FROM t
24+
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
25+
AND ( coalesce("CONTROL_FLAG", 1) = 1
26+
OR coalesce("CONTROL_FLAG", 1) = 3 )
27+
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
28+
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
29+
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );
30+
31+
exec select prev_sql_id into :sqlid from v$session where sid=sys_context('userenv','sid');
32+
33+
SELECT /* MYQUERY */ COUNT(*)
34+
FROM t
35+
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
36+
AND ( coalesce("CONTROL_FLAG", 1) = 1
37+
OR coalesce("CONTROL_FLAG", 1) = 3 )
38+
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
39+
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
40+
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );
41+
42+
--
43+
-- Note the poor cardinality estimate of "2"
44+
--
45+
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR());
46+
47+
select distinct table_name,owner,expression_text
48+
from dba_expression_statistics
49+
where (table_name,owner)
50+
in (select object_name, object_owner
51+
from v$sql_plan
52+
where object_type = 'TABLE'
53+
and sql_id = :sqlid);
54+
--
55+
-- Create the expression statistics
56+
--
57+
select dbms_stats.create_extended_stats(USER,'T',
58+
q'[(COALESCE("CONTROL_FLAG",1))]')
59+
from dual;
60+
61+
select dbms_stats.create_extended_stats(USER,'T',
62+
q'[(COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]')
63+
from dual;
64+
65+
begin
66+
dbms_stats.gather_table_stats(USER,'T',
67+
method_opt=>q'[for columns (COALESCE("CONTROL_FLAG",1))]',
68+
no_invalidate=>FALSE);
69+
70+
dbms_stats.gather_table_stats(USER,'T',
71+
method_opt=>q'[for columns (COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]',
72+
no_invalidate=>FALSE);
73+
end;
74+
/
75+
76+
SELECT /* MYQUERY */ COUNT(*)
77+
FROM t
78+
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
79+
AND ( coalesce("CONTROL_FLAG", 1) = 1
80+
OR coalesce("CONTROL_FLAG", 1) = 3 )
81+
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
82+
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
83+
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );
84+
85+
--
86+
-- Note the improved cardinality estimate
87+
--
88+
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR());
89+
90+
spool off

0 commit comments

Comments
 (0)