Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions optimizer/expression_stats/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Small demo to show how expression statistics can improve cardinality estimates

# Disclaimer

<br/>-- These scripts are provided for educational purposes only.
<br/>-- They are NOT supported by Oracle World Wide Technical Support.
<br/>-- The scripts have been tested and they appear to work as intended.
<br/>-- You should always run scripts on a test instance.


124 changes: 124 additions & 0 deletions optimizer/expression_stats/expression.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@

Table created.


COUNT(*)
----------
1773


PL/SQL procedure successfully completed.


COUNT(*)
----------
1773


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID 8caz15dwj8w8k, child number 0
-------------------------------------
SELECT /* MYQUERY */ COUNT(*) FROM t WHERE ( "DELIVERY_DATE" >=
trunc(sysdate@!, 'fmyear') AND ( coalesce("CONTROL_FLAG", 1) = 1
OR coalesce("CONTROL_FLAG", 1) = 3 ) AND (
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1' OR
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' ) AND
"DELIVERY_DATE" <= trunc(sysdate@! - 1) )

Plan hash value: 1010173228


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 9 (100)| |
| 1 | SORT AGGREGATE | | 1 | 15 | | |
|* 2 | FILTER | | | | | |
|* 3 | TABLE ACCESS FULL| T | 2 | 30 | 9 (0)| 00:00:01 |
----------------------------------------------------------------------------

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

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

2 - filter(TRUNC(SYSDATE@!-1)>=TRUNC(SYSDATE@!,'fmyear'))
3 - filter(((COALESCE("CONTROL_FLAG",1)=1 OR
COALESCE("CONTROL_FLAG",1)=3) AND "DELIVERY_DATE"<=TRUNC(SYSDATE@!-1)
AND (COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')='1' OR
COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')='3') AND
"DELIVERY_DATE">=TRUNC(SYSDATE@!,'fmyear')))


30 rows selected.


TABLE_NAME OWNER EXPRESSION_TEXT
---------------------------------------- ---------------------------------------- ----------------------------------------------------------------------------------------------------
T ADHOC COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1')
T ADHOC "DELIVERY_DATE"
T ADHOC COALESCE("CONTROL_FLAG",1)


DBMS_STATS.CREATE_EXTENDED_STATS(USER,'T',Q'[(COALESCE("CONTROL_FLAG",1))]')
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SYS_STUARLGZBSAG4YYL$Q$14300KT


DBMS_STATS.CREATE_EXTENDED_STATS(USER,'T',Q'[(COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]')
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SYS_STU2K568KT2T5R6S37VQUN63#V


PL/SQL procedure successfully completed.


COUNT(*)
----------
1773


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID 8caz15dwj8w8k, child number 0
-------------------------------------
SELECT /* MYQUERY */ COUNT(*) FROM t WHERE ( "DELIVERY_DATE" >=
trunc(sysdate@!, 'fmyear') AND ( coalesce("CONTROL_FLAG", 1) = 1
OR coalesce("CONTROL_FLAG", 1) = 3 ) AND (
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1' OR
coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' ) AND
"DELIVERY_DATE" <= trunc(sysdate@! - 1) )

Plan hash value: 1010173228


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 10 (100)| |
| 1 | SORT AGGREGATE | | 1 | 13 | | |
|* 2 | FILTER | | | | | |
|* 3 | TABLE ACCESS FULL| T | 1363 | 17719 | 10 (10)| 00:00:01 |
----------------------------------------------------------------------------

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

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

2 - filter(TRUNC(SYSDATE@!-1)>=TRUNC(SYSDATE@!,'fmyear'))
3 - filter(("DELIVERY_DATE"<=TRUNC(SYSDATE@!-1) AND
COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1') AND
"DELIVERY_DATE">=TRUNC(SYSDATE@!,'fmyear') AND
COALESCE("CONTROL_FLAG",1)))


29 rows selected.

90 changes: 90 additions & 0 deletions optimizer/expression_stats/expression.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
spool expression
--
-- Demonstrates the usefulness of expression statistics
-- Creates a table "T" - and note that session requires
-- read access to V$SESSION
--
set linesize 250
set trims on
set tab off
column plan_table_output format a100
column expression_text format a100
column table_name format a40
column owner format a40

var sqlid varchar2(20)

create table t as
select sysdate-50+rownum/100 delivery_date,1 control_flag,
rownum account_id
from dual connect by rownum<=10000;

SELECT /* MYQUERY */ COUNT(*)
FROM t
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
AND ( coalesce("CONTROL_FLAG", 1) = 1
OR coalesce("CONTROL_FLAG", 1) = 3 )
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );

exec select prev_sql_id into :sqlid from v$session where sid=sys_context('userenv','sid');

SELECT /* MYQUERY */ COUNT(*)
FROM t
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
AND ( coalesce("CONTROL_FLAG", 1) = 1
OR coalesce("CONTROL_FLAG", 1) = 3 )
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );

--
-- Note the poor cardinality estimate of "2"
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR());

select distinct table_name,owner,expression_text
from dba_expression_statistics
where (table_name,owner)
in (select object_name, object_owner
from v$sql_plan
where object_type = 'TABLE'
and sql_id = :sqlid);
--
-- Create the expression statistics
--
select dbms_stats.create_extended_stats(USER,'T',
q'[(COALESCE("CONTROL_FLAG",1))]')
from dual;

select dbms_stats.create_extended_stats(USER,'T',
q'[(COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]')
from dual;

begin
dbms_stats.gather_table_stats(USER,'T',
method_opt=>q'[for columns (COALESCE("CONTROL_FLAG",1))]',
no_invalidate=>FALSE);

dbms_stats.gather_table_stats(USER,'T',
method_opt=>q'[for columns (COALESCE(SUBSTR(TO_CHAR("ACCOUNT_ID"),4,1),'1'))]',
no_invalidate=>FALSE);
end;
/

SELECT /* MYQUERY */ COUNT(*)
FROM t
WHERE ( "DELIVERY_DATE" >= trunc(sysdate@!, 'fmyear')
AND ( coalesce("CONTROL_FLAG", 1) = 1
OR coalesce("CONTROL_FLAG", 1) = 3 )
AND ( coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '1'
OR coalesce(substr(to_char("ACCOUNT_ID"), 4, 1), '1') = '3' )
AND "DELIVERY_DATE" <= trunc(sysdate@! - 1) );

--
-- Note the improved cardinality estimate
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR());

spool off