Slides from OOW13
The optimizer must try to be all things to all people, and similarly, the collection of optimizer statistics must try to satisfy the needs of all. And many DBA's just leave it at that. But the optimizer offers so much more than that. With a little more effort and discipline, we can achieve much more than a "one-size-fits-all" policy, and maximize the benefit of all of the optimizer features. We'll look at the tools now available under DBMS_STATS to get more stability and better performance with optimizer statistics.
18. 9/26/2013
18
times have changed ...
35
36
SQL> desc DBMS_STATS
FUNCTION CLOB_TO_VARRAY
FUNCTION CONV_RAW
FUNCTION CREATE_EXTENDED_STATS
FUNCTION DIFF_TABLE_STATS_IN_HISTORY
FUNCTION DIFF_TABLE_STATS_IN_PENDING
FUNCTION DIFF_TABLE_STATS_IN_STATTAB
FUNCTION GET_COMPATIBLE
FUNCTION GET_PARAM
FUNCTION GET_PREFS
FUNCTION GET_STATS_HISTORY_AVAILABILITY
FUNCTION GET_STATS_HISTORY_RETENTION
FUNCTION GET_STAT_TAB_VERSION
FUNCTION REPORT_COL_USAGE
FUNCTION REPORT_GATHER_AUTO_STATS
FUNCTION REPORT_GATHER_DATABASE_STATS
FUNCTION REPORT_GATHER_DICTIONARY_STATS
26. 9/26/2013
26
... smarter than you
51
52
SQL> select count(e.hiredate)
2 from DEPT d, EMP e
3 where e.deptno = d.deptno(+)
4 and e.sal > 10;
nested loop outer
sort merge outer
hash hash anti
nested loop anti
27. 9/26/2013
27
53
-------------------------------------------
| Id | Operation | Name | Rows |
-------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | SORT AGGREGATE | | 1 |
|* 2 | TABLE ACCESS FULL| EMP | 14 |
-------------------------------------------
no DEPT ?
54
SQL> select count(e.hiredate)
2 from DEPT d, EMP e
3 where e.deptno = d.deptno(+)
4 and e.sal > 10;
not null
foreign key
key preserved
32. 9/26/2013
32
63
SQL> select client_name, status
2 from DBA_AUTOTASK_CLIENT;
CLIENT_NAME STATUS
------------------------------------ --------
auto optimizer stats collection ENABLED
auto space advisor ENABLED
sql tuning advisor ENABLED
most sites
64
stats every night
default options
61. 9/26/2013
61
121
select *
from PEOPLE
insert into PEOPLE
select * from ...
select ...
from PEOPLE,
DEPT
where ...
delete from T
where X in
( select PID
from PEOPLE )
declare
v people.name%type;
begin
...
SQL> begin
2 dbms_stats.gather_table_stats(
3 'DEMO',
4 'PEOPLE);
5 end;
6 /
122
62. 9/26/2013
62
oracle 9
123
124
SQL> desc DBMS_STATS
PROCEDURE GATHER_TABLE_STATS
Argument Name Type In/Out Default?
----------------------- -------------- ------ --------
OWNNAME VARCHAR2 IN
TABNAME VARCHAR2 IN
PARTNAME VARCHAR2 IN DEFAULT
ESTIMATE_PERCENT NUMBER IN DEFAULT
BLOCK_SAMPLE BOOLEAN IN DEFAULT
METHOD_OPT VARCHAR2 IN DEFAULT
DEGREE NUMBER IN DEFAULT
GRANULARITY VARCHAR2 IN DEFAULT
CASCADE BOOLEAN IN DEFAULT
STATTAB VARCHAR2 IN DEFAULT
STATID VARCHAR2 IN DEFAULT
STATOWN VARCHAR2 IN DEFAULT
NO_INVALIDATE BOOLEAN IN DEFAULT
STATTYPE VARCHAR2 IN DEFAULT
FORCE BOOLEAN IN DEFAULT
NO_INVALIDATE BOOLEAN IN DEFAULT
69. 9/26/2013
69
137
unless things are bad...
do not change statistics
138
Inflammatory
statements
which will
alienate the
audience
Presentation Duration
1
2
120. 9/26/2013
120
239
some real data
239
240
SQL> desc VEHICLE
Name Null? Type
-------------------------- -------- -------------
ID NUMBER
MAKE VARCHAR2(12)
MODEL VARCHAR2(12)
...
SQL> select count(*)
2 from VEHICLE;
COUNT(*)
------------
4,770,662
240
121. 9/26/2013
121
241
default stats not enough
241
242
SQL> select count(*)
2 from VEHICLE
3 where MAKE = 'TOYOTA';
COUNT(*)
----------
608822
------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 18|
| 1 | SORT AGGREGATE | | 1 | 7 | |
|* 2 | INDEX RANGE SCAN| MAKE_IX | 6325 | 44275 | 18|
------------------------------------------------------------
242
148. 9/26/2013
148
see it !
295
SQL> select sql_id,
2 child_number,
3 is_reoptimizable,
4 is_shareable
2 from v$sql s
3 where sql_text like 'select ...';
SQL_ID CHILD_NUMBER I I
------------- ------------ - -
68vghuy0cr298 0 Y N
68vghuy0cr298 1 N Y
296
149. 9/26/2013
149
hangs around
297
SQL> exec dbms_spd.flush_sql_plan_directive;
PL/SQL procedure successfully completed.
SQL> select d.type, d.reason, o.object_name
2 from dba_sql_plan_directives d,
3 dba_sql_plan_dir_objects o
4 where o.directive_id = d.directive_id
5 and o.owner = 'SCOTT';
TYPE REASON OBJ
---------------- ------------------------------------ -----
DYNAMIC_SAMPLING SINGLE TABLE CARDINALITY MISESTIMATE DEPT
298
167. 9/26/2013
167
333
SQL> desc DBA_TABLES
Name Null? Type
----------------------------- -------- -------------
OWNER NOT NULL VARCHAR2(30)
TABLE_NAME NOT NULL VARCHAR2(30)
COLUMN_NAME NOT NULL VARCHAR2(30)
...
NUM_ROWS NUMBER
334
SQL> desc DBA_TAB_COLS
Name Null? Type
----------------------------- -------- -------------
OWNER NOT NULL VARCHAR2(30)
TABLE_NAME NOT NULL VARCHAR2(30)
COLUMN_NAME NOT NULL VARCHAR2(30)
...
NUM_DISTINCT NUMBER
LOW_VALUE RAW(32)
HIGH_VALUE RAW(32)
...
168. 9/26/2013
168
335
SQL> desc PEOPLE
Name Null? Type
----------------------------- -------- -------------
PID NUMBER
GENDER CHAR(1)
NAME VARCHAR2(47)
AGE NUMBER
336
SQL> alter session set sql_true = true;
Session altered.
SQL> begin
2 dbms_stats.gather_table_stats(
3 'DEMO',
4 'PEOPLE);
5 end;
6 /
177. 9/26/2013
177
353
96 127
354
SQL> set serverout on
SQL> declare
2 type t_bucket is table of varchar2(1);
3 l_synopsis t_bucket;
4 l_splits number := 0;
5 l_hash int;
6 l_min_val int := 0;
7 l_synopsis_size int := 16;
8 begin
9 for i in ( select single_char from one_pass ) loop
10 l_hash := ascii(i.single_char);
11
12 if l_synopsis.count = l_synopsis_size then
13 l_min_val :=
14 case
15 when l_min_val = 0 then 64
16 when l_min_val = 64 then 96
17 when l_min_val = 96 then 112
18 when l_min_val = 112 then 120
19 end;
20 l_splits := l_splits + 1;
178. 9/26/2013
178
355
22
23 for j in 1 .. l_min_val loop
24 if l_synopsis.exists(j) then
25 l_synopsis.delete(j);
26 end if;
27 end loop;
28 end if;
29
30 if l_hash > l_min_val then
31 l_synopsis(l_hash) := 'Y';
32 end if;
33 end loop;
34 dbms_output.put_line(l_synopsis.count *
35 power(2,l_splits));
36 end;
37 /
Splitting, keeping entries above 64
Splitting, keeping entries above 96
Splitting, keeping entries above 112
88
356
the reality
16384 bucket limit
18,446,744,073,709,551,616 hash range
195. 9/26/2013
195
389
SQL> desc SYS.COL_USAGE$
Name Null? Type
----------------------- -------- ---------
OBJ# NUMBER
INTCOL# NUMBER
EQUALITY_PREDS NUMBER
EQUIJOIN_PREDS NUMBER
NONEQUIJOIN_PREDS NUMBER
RANGE_PREDS NUMBER
LIKE_PREDS NUMBER
NULL_PREDS NUMBER
TIMESTAMP DATE
390
Oracle doesn’t know ...
202. 9/26/2013
202
403
boudary conditions
404
SQL> create table T (
2 skew varchar2(10),
3 even number);
Table created.
SQL> insert into T
2 select
3 case
4 when rownum > 99995 then 'SPECIAL'
5 else dbms_random.string('U',8)
6 end,
7 mod(rownum,200)
8 from dual
9 connect by level <= 100000
10 /
100000 rows created.
5 special
values
even
distribution
203. 9/26/2013
203
405
SQL> exec dbms_stats.gather_table_stats(
user,'T', estimate_percent=>null);
PL/SQL procedure successfully completed.
SQL> select COLUMN_NAME,NUM_DISTINCT,DENSITY,
2 ( select count(*)
3 from user_tab_histograms
4 where table_name = 'T'
5 and column_name = c.column_name )
6 from user_tab_cols c
7 where table_name = 'T'
8 order by table_name,COLUMN_ID
9 /
COLUMN_NAME NUM_DISTINCT DENSITY HIST_CNT
------------------- ------------ ---------- ----------
SKEW 99996 .00001 2
EVEN 200 .005 2
406
SQL> select * from T where skew = 'SPECIAL';
SKEW VAL
---------- ----------
SPECIAL 196
SPECIAL 197
SPECIAL 198
SPECIAL 199
SPECIAL 0
5 rows selected.
SQL> select * from T where even = 5;
TAG VAL
---------- ----------
IBRXGVIE 5
[snip]
500 rows selected.
204. 9/26/2013
204
407
SQL> exec dbms_stats.gather_table_stats(
user,'T', estimate_percent=>null);
PL/SQL procedure successfully completed.
SQL> select COLUMN_NAME,NUM_DISTINCT,DENSITY,
2 ( select count(*)
3 from user_tab_histograms
4 where table_name = 'T'
5 and column_name = c.column_name )
6 from user_tab_cols c
7 where table_name = 'T'
8 order by table_name,COLUMN_ID
9 /
COLUMN_NAME NUM_DISTINCT DENSITY HIST_CNT
------------------- ------------ ---------- ----------
SKEW 99996 .00001 2
EVEN 200 .000005 200
408
recommendation #5
213. 9/26/2013
213
425
analyze ... validate structure
426
SQL> desc INDEX_STATS
Name Null? Type
----------------------------- -------- --------------
HEIGHT NUMBER
BLOCKS NUMBER
NAME VARCHAR2(30)
PARTITION_NAME VARCHAR2(30)
...
OPT_CMPR_COUNT NUMBER
OPT_CMPR_PCTSAVE NUMBER
214. 9/26/2013
214
427
wrap up
428
don't collect stats .... unless
don't collect system stats ... unless
don't collect histograms ... unless
default estimate size (NDV)
lie and cheat