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
expression stats example
  • Loading branch information
nigelbayliss committed Aug 3, 2021
commit d1f252bb5a8e9feed6fa6f63bb6c3c0eb40ac552
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