Connor McDonald
OracleDBA
co.uk
1
@connor_mc_d
connormcdonald.wordpress.com
2
gratuitous book plug
4
bio slide
5
7
8
you should look cool
9
10
11
Dump of memory from 0x07246400 to 0x07248400
1064B4C00 06A20000 08C0000A 0A07C47E 00020506 [...........~....]
1064B4C10 34BC0000 01000000 00030CBF 0A07C47C [4..............|]
1064B4C20 0002EC28 00020300 00000000 0004001D [...(............]
...
1064B6BF0 C10B02C1 0B06436F 6E6E6F72 C47E0605 [......Connor.~..]
table or index
block size
database version created in
relative block address
12
sounds sexy right ?
13
14
if you are tuning SQL ...
15
... you are failing
16
17
why ?
18
real example
19
20
21
"last transaction for all accounts"
problem
22
23
make it faster ...
24
"it’s a SQL problem"
25
26
SQL> desc ACCOUNT
Name Null? Type
----------------------------------- -------- ------------------------
ACCOUNT_NUM NOT NULL NUMBER(8)
CURRENT_BALANCE NOT NULL NUMBER(14,2)
...
SQL> desc TRANSACTIONS
Name Null? Type
----------------------------------- -------- -------------------
TXN_SEQ NOT NULL NUMBER(11)
TXN_TS NOT NULL TIMESTAMP(6)
TXN_TYPE NOT NULL VARCHAR2(10)
ACCOUNT_NUM NOT NULL NUMBER(8)
AMOUNT NOT NULL NUMBER(11,2)
existing code
27
28
SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS
2 from TRANSACTIONS, ACCOUNT
3 where <joins etc>
4 group by ACCOUNT_NUM
5 order by 1;
29
SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS
2 from TRANSACTIONS
3 group by ACCOUNT_NUM
4 order by 1;
simplified
30
SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS
2 from TRANSACTIONS t
3 group by ACCOUNT_NUM
4 order by 1;
--------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS FULL | TRANSACTIONS |
--------------------------------------------------
tuning attempt #1
31
32
SQL> select /*+ PARALLEL(t 16) */
2 ACCOUNT_NUM, max(TXN_TS) LAST_TS
3 from TRANSACTIONS t
4 group by ACCOUNT_NUM
5 order by 1;
worked...
33
... storage meltdown
34
tuning attempt #2
35
36
create index TRANSACTIONS_IX on TRANSACTIONS (
account_num, txn_ts )
SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS
2 from TRANSACTIONS t
3 group by ACCOUNT_NUM
4 order by 1;
--------------------------------------------------
| Id | Operation | Name |
--------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | INDEX FAST FULL SCAN| TRANSACTIONS_IX |
--------------------------------------------------
worked...
37
... oltp impact
38
tuning attempt #3
39
40
CREATE TABLE TRANSACTIONS
(
...
)
PARTITION BY RANGE (TXN_TS)
INTERVAL( NUMTOYMINTERVAL(1,'MONTH'))
(
PARTITION P1 VALUES LESS THAN (TIMESTAMP' 2009-01-01 00:00:00')
PARTITION P2 VALUES LESS THAN (TIMESTAMP' 2009-06-01 00:00:00')
...
);
41
SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS
2 from TRANSACTIONS t
3 where TXN_TS > add_months(sysdate,-12)
4 group by ACCOUNT_NUM
5 order by 1;
42
---------------------------------------------------------------
| Id | Operation | Name |Pstart| Pstop |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | | |
| 1 | PARTITION RANGE ITER..| | 127 | 138 |
|* 2 | TABLE ACCESS FULL | TRANSACTIONS | 127 | 138 |
-------------------------------------------------------------
worked ...
43
... changed the function
44
45
tuning attempt #4
47
48
Jul Aug Sep Oct
49
SQL> insert into GTT_LAST_TXN
2 select ACCOUNT_NUM, max(TXN_TS) LAST_TS
3 from TRANSACTIONS t
4 where TXN_TS >= trunc(sysdate,'MM')
5 group by ACCOUNT_NUM;
for i in (
select ACCOUNT_NUM from ACCOUNTS
minus
select ACCOUNT_NUM from GTT_LAST_TXN
)
insert into GTT_LAST_TXN
select /*+ INDEX_DESC(t (account_num, txn_ts)) */ MAX(TXN_TS)
from TRANSACTIONS t
where ACCOUNT_NUM = i.ACCOUNT_NUM
and TXN_TS < trunc(sysdate,'MM')
worked ...
50
... complexity !
51
problem
52
53
SQL> select ...
2 from ...
3 where ...
the requirement
54
55
"we have an interest in recent
activity for account holders"
"last transaction for all accounts"
promotional material
56
"we haven't seen you in a while,
here's a discount on ...."
57
manual examination
58
tuning attempt #5
59
60
SQL> desc ACCOUNT
Name Null? Type
----------------------------------- -------- ---------------
ACCOUNT_NUM NOT NULL NUMBER(8)
CURRENT_BALANCE NOT NULL NUMBER(14,2)
...
...
...
MODIFICATION_TS NOT NULL TIMESTAMP(6)
optimistic locking
61
62
select ..., MODIFICATION_TS
into ..., :prev_modtstamp
from ACCOUNT
where ...
update ACCOUNT
set ...
where ACCOUNT_NUM = :b1
and MODIFICATION_TS = :prev_modtstamp
if SQL%NOTFOUND then
msg('Row has been changed by another user, please requery');
end if;
63
SQL> select ACCOUNT_NUM,
2 MODIFICATION_TS approx_last_usage
3 from ACCOUNT
that's it !
64
later ...
65
66
SQL> desc ACCOUNT
Name Null? Type
------------------------------- -------- --------------
ACCOUNT_NUM NOT NULL NUMBER(8)
CURRENT_BALANCE NOT NULL NUMBER(14,2)
...
67
update ACCOUNT
set ...
where ACCOUNT_NUM = :b1
and MODIFICATION_TS = :prev_modtstamp
LAST_TXN_TS = systimestamp
LARGEST_TXN_AMT = greatest(TXN_AMT,LARGEST_TXN_AMT)
BALANCE_CEILING = greatest(BALANCE,BALANCE_CEILING)
BALANCE_FLOOR = least(BALANCE,BALANCE_FLOOR)
68
SQL> desc ACCOUNT
Name Null? Type
----------------------------------- -------- ---------------
ACCOUNT_NUM NOT NULL NUMBER(8)
CURRENT_BALANCE NOT NULL NUMBER(14,2)
LAST_WITHDRAWAL_TS TIMESTAMP(6)
LAST_DEPOSIT_TS TIMESTAMP(6)
LAST_TXN_TS TIMESTAMP(6)
LARGEST_TXN_AMT NUMBER(14,2)
BALANCE_CEILING NUMBER(14,2)
BALANCE_FLOOR NUMBER(14,2)
minimal cost
69
(semi) automate
70
"we haven't seen you in a while,
here's a discount on ...."
too focused on the SQL
71
so...
72
if you don't tune SQL ...
73
...what are you tuning ?
74
75
HERE
user experience
76
UX
77
screen...
78
... user experience
79
report....
80
... user experience
81
nightly batch...
82
... user experience
83
all solutions shown ...
84
denormalised
indexes
structure
horse power
... all valid
85
as long as
86
tuning the requirement
87
tuning the user experience
88
SQL as a means, not an end
89
</rant>
90
so if we're "failing"…
91
…why talk about
92
93
94
sql tuning is ...
95
96
stop the bleeding...
97
...until find a cure
98
but ... without
99
... side effects
100
every pain problem
101
102
... side effects
103
104
constipation
dizziness
drowsiness
headache
lightheadedness
nausea
mood swingssweating
vomitingrash
itching
difficulty breathing
tightness in the chest
swelling of the mouth
confusion
disorientation
fainting
irregular heartbeat
hallucinations
seizures
sudden chest pain
unusual bruising or bleeding
blurred vision
"This is not a complete list"
105
triage
106
find the (likely) pain
stop the bleeding
avoid side effects
work toward cure
find
107
108
where not too look ...
109
(maybe)
server
110
"server CPU is 45%"
111
"buffer cache is 99%"
too high level
112
user experience
113
"no problems last 15 minutes"
114
Statspack
115
(maybe)
hourly...
116
sql trace
117
definitive ... but
118
(maybe) intrusive
119
(maybe) user experience
120
"please repeat"
121
targetted
122
much easier
123
instrumented
124
125
procedure MY_PROC(...) is
begin
dbms_application_info.set_module('MY_PROC');
dai.set_client_info(' p_parm1 = '||p_parm1);
dai.set_client_info(' p_parm2 = '||p_parm2);
select ...
update ...
dai.set_action('now loading changes');
...
end;
diagnostic pack
v$active_session_history
127
amazing
128
every active session...
129
...every second
130
131
SQL> desc V$ACTIVE_SESSION_HISTORY
Name Null? Type
------------------------------- -------- -------------------
SAMPLE_ID NUMBER
SAMPLE_TIME TIMESTAMP(3)
IS_AWR_SAMPLE VARCHAR2(1)
SESSION_ID NUMBER
SESSION_SERIAL# NUMBER
SESSION_TYPE VARCHAR2(10)
FLAGS NUMBER
USER_ID NUMBER
SQL_ID VARCHAR2(13)
IS_SQLID_CURRENT VARCHAR2(1)
SQL_CHILD_NUMBER NUMBER
SQL_OPCODE NUMBER
SQL_OPNAME VARCHAR2(64)
FORCE_MATCHING_SIGNATURE NUMBER
TOP_LEVEL_SQL_ID VARCHAR2(13)
TOP_LEVEL_SQL_OPCODE NUMBER
SQL_PLAN_HASH_VALUE NUMBER
SQL_PLAN_LINE_ID NUMBER
SQL_PLAN_OPERATION VARCHAR2(30)
"This morning, my screen froze
for 3 mins running Pay Adjustment..."
132
133
SQL> select sql_id,
2 sql_exec_id,
3 count(*)
4 from v$active_session_history
5 where program = 'Finance.exe'
6 and module = 'PayAdjust'
7 and sample_time >
timestamp '2013-08-20 08:00:00'
8 and sql_id is not null
9 group by
10 sql_id,
11 sql_exec_id
12 order by 3 desc ;
134
SQL_ID SQL_EXEC_ID COUNT(*)
------------- ----------- ----------
087jnbt3bg3fn 33562711 178
9n2nx15wj6tb3 33512732 39
7nvh5pd4y5nqu 33562791 36
7nvh5pd4y5nqu 33562735 30
7nvh5pd4y5nqu 33562736 29
6b5r2j5p2z7kk 33671666 14
6b5r2j5p2z7kk 33670545 12
7nvh5pd4y5nqu 33562689 11
bamffwpy8v8bt 33554432 9
...
135
# cd $ORACLE_HOME/rdbms/admin
# sqlplus / as sysdba @ashrpt
136
very very cool
137
138
SQL> select sql_fulltext
2 from v$sql
3 where sql_id = '087jnbt3bg3fn';
SQL_FULLTEXT
-----------------------------------------------
SELECT ...
FROM ...
139
latching
140
woeful metaphor
143
same with memory
SGA
145
latches
146
serialised access
aka, someone waits
SGA
protected by
SGA
protected by
1) get latch
SGA
protected by
2) access memory
SGA
protected by
3) release latch
151
what protects the latch ?
152
latch acquisition atomic
you can do better
153
154
SQL> select sql_fulltext
2 from v$sqlstats
3 where sql_id = '087jnbt3bg3fn';
SQL_FULLTEXT
-----------------------------------------------
SELECT ...
FROM ...
"The column definitions for columns in V$SQLSTATS are
identical to those in the V$SQL and V$SQLAREA views.
However, the V$SQLSTATS view differs from V$SQL and
V$SQLAREA in that it is faster, more scalable, and has a
greater data retention (the statistics may still appear in
this view, even after the cursor has been aged out of the
shared pool)."
155
156
found your sql...
SQL> select e.department_id, sum(salary)
2 from emp e,
3 job_hist j
4 where e.employee_id = j.employee_id
5 and extract(year from e.hire_date) > 1985
6 and j.end_date > j.start_date + 1
7 and j.start_date >= e.hire_date
8 group by e.department_id
157
stop
158
optimizer got it wrong...
159
or
160
... it cannot run better
161
legitimate response
be like the optimizer
162
only smarter
what does it do ?
163
we can see !
164
10053
165
don't panic....
166
167
SQL> alter session set events =
2 '10053 trace name context forever, level 1';
Session altered.
SQL> explain plan for
2 select e.empno, d.dname
3 from emp e,
4 dept d
5 where e.deptno = d.deptno
6 and e.ename like '%A%'
7 and d.deptno != 5;
Explained.
168
SQL> select p.tracefile
2 from v$session s, v$process p
3 where s.paddr = p.addr
4 and s.sid = sys_context('USERENV','SID');
TRACEFILE
----------------------------------------------
/u01/app/oracle/diag/..../MYDB_ora_2994270.trc
169
---------------------
QUERY BLOCK SIGNATURE
---------------------
signature (): qb_name=SEL$1 nbfros=2 flg=0
fro(0): flg=4 objn=51562 hint_alias="D"@"SEL$1"
fro(1): flg=4 objn=51564 hint_alias="E"@"SEL$1"
******************************************
----- Current SQL Statement (sql_id=gvg2yvpdr4uaw) -----
explain plan for
select e.empno, d.dname
from emp e,
dept d
where e.deptno = d.deptno
and e.ename like '%A%'
and d.deptno != 5
*******************************************
170
******************************
PARAMETERS
******************************
Compilation Environment Dump
optimizer_mode_hinted = false
optimizer_features_hinted = 0.0.0
parallel_execution_enabled = true
parallel_query_forced_dop = 0
parallel_dml_forced_dop = 0
parallel_ddl_forced_degree = 0
parallel_ddl_forced_instances = 0
_query_rewrite_fudge = 90
optimizer_features_enable = 11.2.0.2
_optimizer_search_limit = 5
171
Considering Query Transformations
**************************
*************************
Common Subexpression elimination
Order-by elimination
Join Elimination
*************************
SQL:******* UNPARSED QUERY IS *******
SELECT "E"."EMPNO" "EMPNO","D"."DNAME" "DNAME"
FROM "SCOTT"."EMP" "E","SCOTT"."DEPT" "D"
WHERE "E"."DEPTNO"="D"."DEPTNO"
AND "E"."ENAME" LIKE '%A%'
AND "D"."DEPTNO"<>5
172
Predicate Move-Around (PM)
**************************
"E"."DEPTNO"="D"."DEPTNO" AND
"E"."ENAME" LIKE '%A%'
AND "D"."DEPTNO"<>5
...
finally:
"E"."DEPTNO"="D"."DEPTNO" AND
"E"."ENAME" LIKE '%A%' AND
"D"."DEPTNO"<>5 AND
"E"."DEPTNO"<>5
173
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for EMP[E]
Table: EMP Alias: E
Card: Original: 14.000000 Rounded: 1 Computed: 0.70
Access Path: TableScan
Cost: 4.00 Resp: 4.00 Degree: 0
Cost_io: 4.00 Cost_cpu: 41081
Resp_io: 4.00 Resp_cpu: 41081
Best:: AccessPath: TableScan
Cost: 4.00 Degree: 1 Resp: 4.00 Card: 0.70 Bytes: 0
174
Access path analysis for DEPT
***************************************
SINGLE TABLE ACCESS PATH
Single Table Cardinality Estimation for DEPT[D]
Using prorated density: 0.208333 of col #1 as
selectvity of out-of-range/non-existent value pred
Table: DEPT Alias: D
Card: Original: 4.000000 Rounded: 3 Computed: 3.17
Access Path: TableScan
Cost: 4.00 Resp: 4.00 Degree: 0
Cost_io: 4.00 Cost_cpu: 36467
Resp_io: 4.00 Resp_cpu: 36467
Best:: AccessPath: TableScan
Cost: 4.00 Degree: 1 Resp: 4.00 Card: 3.17 Bytes: 0
175
Join order[1]: EMP[E]#0 DEPT[D]#1
***************
Now joining: DEPT[D]#1
***************
NL Join
Outer table: Card: 0.70 Cost: 4.00 Resp: 4.00 Degree: 1
Bytes: 13
Access path analysis for DEPT
Access Path: TableScan
Access Path: index (UniqueScan)
Index: PK_DEPT
176
SM Join
SM cost: 10.01
Outer table: EMP Alias: E
resc: 4.00 card 0.70 bytes: 13 deg: 1 resp: 4.00
Inner table: DEPT Alias: D
resc: 4.00 card: 3.17 bytes: 13 deg: 1 resp: 4.00
HA Join
HA cost: 8.51
resc: 8.51 resc_io: 8.00 resc_cpu: 4367998
resp: 8.51 resp_io: 8.00 resp_cpu: 4367998
Best:: JoinMethod: NestedLoop
Cost: 5.01 Degree: 1 Resp: 5.01 Card: 0.55 Bytes: 26
177
Join order[2]: DEPT[D]#1 EMP[E]#0
***************
Now joining: EMP[E]#0
***************
NL Join
...
SM Join
...
HA Join
...
178
------------------------------------------------+---------------+
| Id | Operation | Name | Rows | Cost |
------------------------------------------------+----------------
| 0 | SELECT STATEMENT | | | 5 |
| 1 | NESTED LOOPS | | | |
| 2 | NESTED LOOPS | | 1 | 5 |
| 3 | TABLE ACCESS FULL | EMP | 1 | 4 |
| 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 1 |
------------------------------------------------+---------------+
the optimizer does ...
179
can I write it better ?
180
CONSIDERING QUERY TRANSFORMATIONS
where should I start ?
181
SINGLE TABLE ACCESS PATH
what should I join to (next) ?
182
Join order[1]: EMP[E]#0 DEPT[D]#1
how should I join ?
183
NL Join
HA Join
SM Join
we follow its lead
184
what is the real query
185
186
SQL> set autotrace traceonly stat
SQL> select * from STUFF
2 where CREATED > sysdate
Statistics
------------------------------------------
651 recursive calls
0 db block gets
2243 consistent gets
24 physical reads
12c
187
188
SQL> variable c clob
SQL> begin
2 dbms_utility.expand_sql_text
3 ( 'select * from STUFF '||
4 'where created > sysdate',:c);
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> print c
189
SQL> create or replace
2 view STUFF as
3 select
4 o.owner,
5 o.created,
6 s.bytes,
7 s.tablespace_name
8 from
9 dba_segments s,
10 all_objects o
11 where o.owner = s.owner
12 and o.object_name = s.segment_name;
View created.
190
SELECT "A1"."OWNER" "OWNER",
"A1"."NAME" "NAME",
"A1"."CREATED" "CREATED",
"A1"."BYTES" "BYTES",
"A1"."TABLESPACE_NAME" "TABLESPACE_NAME"
FROM (SELECT "A2"."OWNER" "OWNER",
"A2"."OBJECT_NAME" "NAME",
"A2"."CREATED" "CREATED",
"A3"."BYTES" "BYTES",
"A3"."TABLESPACE_NAME" "TABLESPACE_NAME" FROM (SELECT "A4"
."OWNER" "OWNER",
"A4"."SEGMENT_NAME" "SEGMENT_NAME",
"A4"."PARTITION_NAME" "PARTITION_NAME",
"A4"."SEGMENT_TYPE" "SEGMENT_TYPE",
"A4"."SEGMENT_SUBTYPE" "SEGMENT_SUBTYPE",
"A4"."TABLESPACE_NAME" "TABLESPACE_NAME",
"A4"."HEADER_FILE" "HEADER_FILE",
"A4"."HEADER_BLOCK" "HEADER_BLOCK",
DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072,
"A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1,
"SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID",
"A4"."RELATIVE_FNO",
"A4"."HEADER_BLOCK",
"A4"."SEGMENT_TYPE_ID",
"A4"."BUFFER_POOL_ID",
"A4"."SEGMENT_FLAGS",
"A4"."SEGMENT_OBJD",
"A4"."BLOCKS"),
"A4"."BLOCKS"))*"A4"."BLOCKSIZE" "BYTES",
DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072,
"A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1,
"SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID",
"A4"."RELATIVE_FNO",
191
"A4"."HEADER_BLOCK",
"A4"."SEGMENT_TYPE_ID",
"A4"."BUFFER_POOL_ID",
"A4"."SEGMENT_FLAGS",
"A4"."SEGMENT_OBJD",
"A4"."BLOCKS"),
"A4"."BLOCKS")) "BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072,
"A4"."EXTENTS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1,
"SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_EXTENTS"("A4"."TABLESPACE_ID",
"A4"."RELATIVE_FNO",
"A4"."HEADER_BLOCK",
"A4"."SEGMENT_TYPE_ID",
"A4"."BUFFER_POOL_ID",
"A4"."SEGMENT_FLAGS",
"A4"."SEGMENT_OBJD",
"A4"."EXTENTS"),
"A4"."EXTENTS")) "EXTENTS",
"A4"."INITIAL_EXTENT" "INITIAL_EXTENT",
"A4"."NEXT_EXTENT" "NEXT_EXTENT",
"A4"."MIN_EXTENTS" "MIN_EXTENTS",
"A4"."MAX_EXTENTS" "MAX_EXTENTS",
"A4"."MAX_SIZE" "MAX_SIZE",
"A4"."RETENTION" "RETENTION",
"A4"."MINRETENTION" "MINRETENTION",
"A4"."PCT_INCREASE" "PCT_INCREASE",
"A4"."FREELISTS" "FREELISTS",
"A4"."FREELIST_GROUPS" "FREELIST_GROUPS",
"A4"."RELATIVE_FNO" "RELATIVE_FNO",
DECODE("A4"."BUFFER_POOL_ID",1,'KEEP',2,'RECYCLE','DEFAULT') "BUFFER_POOL",
DECODE("A4"."FLASH_CACHE",1,'KEEP',2,
'NONE','DEFAULT') "FLASH_CACHE",DECODE("A4"."CELL_FLASH_CACHE",1,'KEEP',2,'NONE','DEFAULT')
"CELL_FLASH_CACHE"
FROM ( (SELECT NVL("A199"."NAME",'SYS') "OWNER",
"A198"."NAME" "SEGMENT_NAME",
192
"A198"."SUBNAME" "PARTITION_NAME",
"A196"."OBJECT_TYPE" "SEGMENT_TYPE",
"A195"."TYPE#" "SEGMENT_TYPE_ID",DECODE(BIT
AND("A195"."SPARE1",2097408),2097152,'SECUREFILE',256,'ASSM','MSSM') "SEGMENT_SUBTYPE",
"A197"."TS#" "TABLESPACE_ID",
"A197"."NAME" "TABLESPACE_NAME",
"A197"."BLOCKSIZE" "BLOCKSIZE",
"A194"."FILE#" "HEADER_FILE",
"A195"."BLOCK#" "HEADER_BLOCK",
"A195"."BLOCKS"*"A197"."BLOCKSIZE" "BYTES",
"A195"."BLOCKS" "BLOCKS",
"A195"."EXTENTS" "EXTENTS",
"A195"."INIEXTS"*"A197"."BLOCKSIZE" "INITIAL_EXTENT",
"A195"."EXTSIZE"*"A197"."BLOCKSIZE" "NEXT_EXTENT",
"A195"."MINEXTS" "MIN_EXTENTS",
"A195"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A195"."SPARE1",4194304),4194304,
"A195"."BITMAPRANGES",NULL) "MAX_SIZE",TO_CHAR(DECODE(
BITAND("A195"."SPARE1",2097152),2097152,
DECODE("A195"."LISTS",0,'NONE',1,'AUTO',2,'MIN',3,'MAX',4,'DEFAULT','INVALID'),NULL))
"RETENTION",DECODE(BITAND("A195"."SPARE1",2097152),2097152,
"A195"."GROUPS",NULL) "MINRETENTION",DECODE(BITAND("A197"."FLAGS",3),1,TO_NUMBER(NULL),
"A195"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A197"."FLAGS",32),32,
TO_NUMBER(NULL),DECODE("A195"."LISTS",0,1,
"A195"."LISTS"))
"FREELISTS",DECODE(BITAND("A197"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A195"."GROUPS",0,1,
"A195"."GROUPS")) "FREELIST_GROUPS",
"A195"."FILE#" "RELATIVE_FNO",BITAND("A195"."CACHEHINT",3) "BUFFER_POOL_ID",
BITAND("A195"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A195"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",
NVL("A195"."SPARE1",0)
"SEGMENT_FLAGS",DECODE(BITAND("A195"."SPARE1",1),1,
"A195"."HWMINCR",
"A198"."DATAOBJ#") "SEGMENT_OBJD" FROM "SYS"."USER$" "A199",
"SYS"."OBJ$" "A198",
"SYS"."TS$" "A197", ( (SELECT
193
DECODE(BITAND("A209"."PROPERTY",8192),8192,'NESTED TABLE','TABLE') "OBJECT_TYPE",
2 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID",
"A209"."OBJ#" "OBJECT_ID",
"A209"."FILE#" "HEADER_FILE",
"A209"."BLOCK#" "HEADER_BLOCK",
"A209"."TS#" "TS_NUMBER" FROM "SYS"."TAB$" "A209" WHERE BITAND("A209"."PROPERTY",1024)=0) UNI
ON ALL (SELECT 'TABLE PARTITION' "OBJECT_TYPE",19 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID",
"A208"."OBJ#" "OBJECT_ID",
"A208"."FILE#" "HEADER_FILE",
"A208"."BLOCK#" "HEADER_BLOCK",
"A208"."TS#" "TS_NUMBER" FROM "SYS"."TABPART$" "A208") UNION ALL
(SELECT 'CLUSTER' "OBJECT_TYPE",3 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID",
"A207"."OBJ#" "OBJECT_ID",
"A207"."FILE#" "HEADER_FILE",
"A207"."BLOCK#" "HEADER_BLOCK",
"A207"."TS#" "TS_NUMBER" FROM "SYS"."CLU$" "A207") UNION ALL
(SELECT DECODE("A206"."TYPE#",8,'LOBINDEX','INDEX') "OBJECT_TYPE",1 "OBJECT_TYPE_ID",6
"SEGMENT_TYPE_ID",
"A206"."OBJ#" "OBJECT_ID",
"A206"."FILE#" "HEADER_FILE",
"A206"."BLOCK#" "HEADER_BLOCK",
"A206"."TS#" "TS_NUMBER" FROM "SYS"."IND$" "A206" WHERE "A206"."TYPE#"=1 OR
"A206"."TYPE#"=2 OR
"A206"."TYPE#"=3 OR
"A206"."TYPE#"=4 OR
"A206"."TYPE#"=6 OR
"A206"."TYPE#"=7 OR
"A206"."TYPE#"=8 OR
"A206"."TYPE#"=9) UNION ALL
(SELECT 'INDEX PARTITION'
"OBJECT_TYPE",20 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID",
"A205"."OBJ#" "OBJECT_ID",
"A205"."FILE#" "HEADER_FILE",
"A205"."BLOCK#" "HEADER_BLOCK",
194
"A205"."TS#" "TS_NUMBER" FROM "SYS"."INDPART$" "A205") UNION ALL
(SELECT 'LOBSEGMENT' "OBJECT_TYPE",21 "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID",
"A204"."LOBJ#" "OBJECT_ID",
"A204"."FILE#" "HEADER_FILE",
"A204"."BLOCK#" "HEADER_BLOCK",
"A204"."TS#" "TS_NUMBER" FROM "SYS"."LOB$" "A204" WHERE BITAND("A204"."PROPERTY",64)=0 OR
BITAND("A204"."PROPERTY",128)=128) UNION ALL
(SELECT 'TABLE SUBPARTITION' "OBJECT_TYPE",34 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID",
"A203"."OBJ#" "OBJECT_ID",
"A203"."FILE#" "HEADER_FILE",
"A203"."BLOCK#" "HEADER_BLOCK",
"A203"."TS#" "TS_NUMBER" FROM "SYS"."TABSUBPART$" "A203") UNION ALL
(SELECT 'INDEX SUBPARTITION' "OBJECT_TYPE",35 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID",
"A202"."OBJ#" "OBJECT_ID",
"A202"."FILE#" "HEADER_FILE",
"A202"."BLOCK#" "HEADER_BLOCK",
"A202"."TS#" "TS_NUMBER" FROM "SYS"."INDSUBPART$" "A202") UNION ALL
(SELECT DECODE("A201"."FRAGTYPE$",'P','LOB PARTITION','LOB SUBPARTITION')
"OBJECT_TYPE",DECODE("A201"."FRAGTYPE$",'P',40,41) "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID",
"A201"."FRAGOBJ#" "OBJECT_ID",
"A201"."FILE#" "HEADER_FILE",
"A201"."BLOCK#" "HEADER_BLOCK",
"A201"."TS#" "TS_NUMBER" FROM "SYS"."LOBFRAG$" "A201")) "A196",
"SYS"."SEG$" "A195",
"SYS"."FILE$" "A194" WHERE "A195"."FILE#"="A196"."HEADER_FILE" AND
"A195"."BLOCK#"="A196"."HEADER_BLOCK" AND
"A195"."TS#"="A196"."TS_NUMBER" AND
"A195"."TS#"="A197"."TS#" AND
"A198"."OBJ#"="A196"."OBJECT_ID" AND
"A198"."OWNER#"="A199"."USER#"(+) AND
"A195"."TYPE#"="A196"."SEGMENT_TYPE_ID" AND
"A198"."TYPE#"="A196"."OBJECT_TYPE_ID" AND
"A195"."TS#"="A194"."TS#" AND
195
"A195"."FILE#"="A194"."RELFILE#") UNION ALL
(SELECT NVL("A193"."NAME",'SYS') "OWNER",
"A191"."NAME" "SEGMENT_NAME",NULL "PARTITION_NAME",
DECODE("A190"."TYPE#",1,'ROLLBACK',10,'TYPE2 UNDO') "SEGMENT_TYPE",
"A190"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE",
"A192"."TS#" "TABLESPACE_ID",
"A192"."NAME" "TABLESPACE_NAME",
"A192"."BLOCKSIZE" "BLOCKSIZE",
"A189"."FILE#" "HEADER_FILE",
"A190"."BLOCK#" "HEADER_BLOCK",
"A190"."BLOCKS"*"A192"."BLOCKSIZE" "BYTES",
"A190"."BLOCKS" "BLOCKS",
"A190"."EXTENTS" "EXTENTS",
"A190"."INIEXTS"*"A192"."BLOCKSIZE" "INITIAL_EXTENT",
"A190"."EXTSIZE"*"A192"."BLOCKSIZE" "NEXT_EXTENT",
"A190"."MINEXTS" "MIN_EXTENTS",
"A190"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A190"."SPARE1",4194304),4194304,
"A190"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION",
"A190"."EXTPCT"
"PCT_INCREASE",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A190"."LISTS",0,1,
"A190"."LISTS")) "FREELISTS",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL),
DECODE("A190"."GROUPS",0,1,"A190"."GROUPS")) "FREELIST_GROUPS",
"A190"."FILE#" "RELATIVE_FNO",BITAND("A190"."CACHEHINT",3)
"BUFFER_POOL_ID",BITAND("A190"."CACHEHINT",12)/4 "FLASH_CACHE",
BITAND("A190"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A190"."SPARE1",0) "SEGMENT_FLAGS",
"A191"."US#" "SEGMENT_OBJD" FROM "SYS"."USER$" "A193","SYS"."TS$" "A192",
"SYS"."UNDO$" "A191",
"SYS"."SEG$" "A190",
"SYS"."FILE$" "A189" WHERE "A190"."FILE#"="A191"."FILE#" AND
"A190"."BLOCK#"="A191"."BLOCK#" AND
"A190"."TS#"="A191"."TS#" AND
"A190"."TS#"="A192"."TS#" AND
"A190"."USER#"="A193"."USER#"(+) AND
("A190"."TYPE#"=1 OR
"A190"."TYPE#"=10) AND
"A191"."STATUS$"<>1 AND
196
"A191"."TS#"="A189"."TS#" AND
"A191"."FILE#"="A189"."RELFILE#") UNION ALL
(SELECT NVL("A188"."NAME",'SYS') "OWNER",
TO_CHAR("A185"."FILE#")||'.'||TO_CHAR("A186"."BLOCK#") "SEGMENT_NAME",NULL "PARTITION_NAME",
DECODE("A186"."TYPE#",2,'DEFERRED ROLLBACK',3,
'TEMPORARY',4,'CACHE',9,'SPACE HEADER','UNDEFINED') "SEGMENT_TYPE",
"A186"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE",
"A187"."TS#" "TABLESPACE_ID",
"A187"."NAME" "TABLESPACE_NAME",
"A187"."BLOCKSIZE" "BLOCKSIZE",
"A185"."FILE#" "HEADER_FILE",
"A186"."BLOCK#" "HEADER_BLOCK",
"A186"."BLOCKS"*"A187"."BLOCKSIZE" "BYTES",
"A186"."BLOCKS" "BLOCKS",
"A186"."EXTENTS" "EXTENTS",
"A186"."INIEXTS"*"A187"."BLOCKSIZE" "INITIAL_EXTENT",
"A186"."EXTSIZE"*"A187"."BLOCKSIZE" "NEXT_EXTENT",
"A186"."MINEXTS" "MIN_EXTENTS",
"A186"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A186"."SPARE1",4194304),4194304,
"A186"."BITMAPRANGES",NULL) "MAX_SIZE",NULL
"RETENTION",NULL "MINRETENTION",DECODE(BITAND("A187"."FLAGS",3),1,TO_NUMBER(NULL),
"A186"."EXTPCT")
"PCT_INCREASE",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."LISTS",0,1,
"A186"."LISTS"))
"FREELISTS",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."GROUPS",0,1,
"A186"."GROUPS")) "FREELIST_GROUPS",
"A186"."FILE#" "RELATIVE_FNO",BITAND("A186"."CACHEHINT",3)
"BUFFER_POOL_ID",BITAND("A186"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A186"."CACHEHINT",48)/16
"CELL_FLASH_CACHE",NVL("A186"."SPARE1",0) "SEGMENT_FLAGS",
"A186"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$"
"A188",
"SYS"."TS$" "A187",
"SYS"."SEG$" "A186",
"SYS"."FILE$" "A185" WHERE "A186"."TS#"="A187"."TS#" AND
"A186"."USER#"="A188"."USER#"(+) AND
"A186"."TYPE#"<>1 AND
"A186"."TYPE#"<>5 AND
197
"A186"."TYPE#"<>6 AND
"A186"."TYPE#"<>8 AND
"A186"."TYPE#"<>10 AND
"A186"."TYPE#"<>11 AND
"A186"."TS#"="A185"."TS#"
AND
"A186"."FILE#"="A185"."RELFILE#") UNION ALL
(SELECT NVL("A184"."NAME",'SYS') "OWNER",'HEATMAP' "SEGMENT_NAME",
NULL "PARTITION_NAME",'SYSTEM STATISTICS' "SEGMENT_TYPE",
"A182"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE",
"A183"."TS#" "TABLESPACE_ID",
"A183"."NAME" "TABLESPACE_NAME",
"A183"."BLO
CKSIZE" "BLOCKSIZE",
"A181"."FILE#" "HEADER_FILE",
"A182"."BLOCK#" "HEADER_BLOCK",
"A182"."BLOCKS"*"A183"."BLOCKSIZE" "BYTES",
"A182"."BLOCKS" "BLOCKS",
"A182"."EXTENTS" "EXTENTS",
"A182"."INIEXTS"*"A183"."BLOCKSIZE" "INITIAL_EXTENT",
"A182"."EXTSIZE"*"A183"."BLOCKSIZE" "NEXT_EXTENT",
"A182"."MINEXTS" "MIN_EXTENTS",
"A182"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A182"."SPARE1",4194304),4194304,
"A182"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL
"MINRETENTION",DECODE(BITAND("A183"."FLAGS",3),1,TO_NUMBER(NULL),
"A182"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DEC
ODE("A182"."LISTS",0,1,
"A182"."LISTS"))
"FREELISTS",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A182"."GROUPS",0,1,
"A182"."GROUPS")) "FREELIST_GROUPS",
"A182"."FILE#" "RELATIVE_FNO",BITAND("A182"."CACHEHINT",3) "BUFFER_POOL_ID",
BITAND("A182"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A18
2"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A182"."SPARE1",0) "SEGMENT_FLAGS",
"A182"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$" "A184",
198
"SYS"."TS$" "A183",
"SYS"."SEG$" "A182",
"SYS"."FILE$" "A181" WHERE "A182"."TS#"="A183"."TS#" AND
"A182"."USER#"="A184"."USER#"(+) AND
"A182"."TYPE#"=11 AND
"A182"."TS#"="A181"."TS#" AND
"A182"."FILE#"="A181"."RELFILE#")) "A4") "A3", (SELECT "A5"."NAME" "OWNER",
"A6"."NAME" "OBJECT_NAME",
"A6"."SUBNAME" "SUBOBJECT_NAME",
"A6"."OBJ#" "OBJECT_ID",
"A6"."DATAOBJ#" "DATA_OBJECT_ID",DECODE("A6"."TYPE#",0,'NEXT OBJECT',1,'INDEX',
2,'TABLE',3,'CLUSTER',4,'VIEW',5,'SYNONYM
',6,'SEQUENCE',7,'PROCEDURE',8,'FUNCTION',9,'PACKAGE',11,'PACKAGE BODY',12,
'TRIGGER',13,'TYPE',14,'TYPE BODY',19,'TABLE PARTITION',20,'INDEX PARTITION',
21,'LOB',22,'LIBRARY',23,'DIRECTORY',24,'QUEUE',28,'JAVA SOURCE',29,'JAVA CLASS',30,
'JAVA RESOURCE',32,'INDEXTYPE',33,'OPERATOR',34,
'TABLE SUBPARTITION',35,'INDEX SUBPARTITION',40,'LOB PARTITION',41,'LOB SUBPARTITION',42
,NVL( (SELECT 'REWRITE EQUIVALENCE' "'REWRITEEQUIVALENCE'" FROM SYS."SUM$" "A52" WHERE "A52"."OBJ#"="A6"."OBJ#" AND
BITAND("A52"."XPFLAGS",8388608)=8388608),'MATERIALIZED VIEW'),43,'DIMENSION',
44,'CONTEXT',46,'RULE SET',47,'RESOURCE PLAN',48,'CONSUMER GROUP',55,'XML SCHEMA',56,'JAVA
DATA',57,'EDITION',59,'RULE',
60,'CAPTURE',61,'APPLY',62,'EVALUATION CONTEXT',66,'JOB',67,'PROGRAM',68,'JOB CLASS',69,
'WINDOW',72,'SCHEDULER GROUP',74,'SCHEDULE',79,'CHAIN',81,'FILE GROUP',82,'MINING
MODEL',87,'ASSEMBLY',90,'CREDENTIAL',92,'CUBE
DIMENSION',93,'CUBE',94,'MEASURE FOLDER',95,'CUBE BUILD PROCESS',100,'FILE WATCHER',
101,'DESTINATION',114,'SQL TRANSLATION PROFILE',115,'UNIFIED AUDIT POLICY','UNDEFINED') "OBJECT_TYPE",
"A6"."CTIME" "CREATED",
"A6"."MTIME" "LAST_DDL_TIME",TO_CHAR("A6"."STIME",'YYYY-MM-DD:HH24:MI:SS') "TIMESTAMP",DEC
ODE("A6"."STATUS",0,'N/A',1,'VALID','INVALID') "STATUS",DECODE(BITAND("A6"."FLAGS",2),0,'N',2,'Y','N')
"TEMPORARY",DECODE(BITAND("A6"."FLAGS",4),0,'N',4,'Y','N') "GENERATED",DECODE(BITAND("A6"."FLAGS",16),0,'N',16,'Y','N')
"SECONDARY",
"A6"."NAMESPACE" "NAMESPACE",
"A6"."DEFINING_EDITION" "EDITION_NAM
E",DECODE(BITAND("A6"."FLAGS",196608),65536,'METADATA LINK',131072,'OBJECT LINK','NONE') "SHARING",
CASE WHEN ("A6"."TYPE#"=4 OR
"A6"."TYPE#"=5 OR
16 ...
199
more
pages
reading a single table
200
should I use an index ?
201
full scan versus index
202
203
SQL> select *
2 from STUDENT
3 where gender = 'W';
full scan
(dba_extents)
File 1, Block 271, 512 blocks
File 2, Block 234, 256 blocks
etc
indexed access
W, File 1, Block 37, Row 4
W, File 1, Block 437, Row 11
Sue
Jane
POOL_IX (POOL_TYPE) STUDENT
what will a full scan cost ?
206
207
SQL> select blocks
2 from dba_tables
3 where owner = 'SCOTT'
4 and table_name = 'STUDENT';
BLOCKS
----------
9083
dbms_space
208
209
SQL> select value
2 from v$parameter
3 where name = 'db_file_multiblock_read_count';
VALUE
---------------
128
IO cost blocks / blocks at a time
210
adjusted downwards
211
adj = 1.6765 x orig0.6581
212
Ack: Wolfgang Brietling, 2001
128
213
41
214
SQL> set autotrace traceonly explain
SQL> select /*+ no_cpu_costing */ * from STUDENT;
-----------------------------------------------------
| Id | Operation | Name | Rows | Cost |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 531K| 224 |
| 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 |
-----------------------------------------------------
9083 / 41 = 221
215
SQL> set autotrace traceonly explain
SQL> select /*+ no_cpu_costing */ * from STUDENT;
-----------------------------------------------------
| Id | Operation | Name | Rows | Cost |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 531K| 224 |
| 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 |
-----------------------------------------------------
9083 / 41 = 221
"digest" the rows
216
217
218
SQL> set autotrace traceonly explain
SQL> select * from STUDENT;
-----------------------------------------------------
| Id | Operation | Name | Rows | Cost |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 531K| 1586 |
| 1 | TABLE ACCESS FULL| STUDENT | 531K| 1586 |
-----------------------------------------------------
what will a index scan cost ?
219
a few blocks +
220
221
SQL> select AVG_LEAF_BLOCKS_PER_KEY
2 from USER_INDEXES
3 where INDEX_NAME = 'STUDENT_IX'
AVG_LEAF_BLOCKS_PER_KEY
-----------------------
6
approximation
222
the easiest way
run a few...
valid use of hints
understanding joins
nested loops
hash
sort merge
index join
and-equal
btree-bitmap conversion
bitmap join
other complexities
bloom filters
parallel
nested loop
"for each row in outer,
check for row in inner"
for (i=1; i<100; i++)
for (j=1; j<100; j++)
for (k=1; k<100; k++)
...
...
demo
cost
effort = L1 + M * L2
=
cost to Lookup rows
in outer table
number of rows Matching
criteria in outer table
cost of Lookup matching row
in inner table
High M ... no good
effort = L1 + M * L2
=
High L2 ... no good
effort = L1 + M * L2
=
High L1 ... no good maybe
effort = L1 + M * L2
sort merge
demo
merge
cost
effort = S1 + S2 + M
sort table 1 (hold result)
sort table 2 (hold result)
merge results (not held*)
risks
RAM
SQL> select value * 0.05 / 1024 sort_kb
2 from v$parameter
3 where name = 'pga_aggregate_target';
SORT_KB
----------
2457.6
single pass
really big sorts
multipass sorts
detection
SQL> select * from v$mystat / v$sesstat / v$sysstat
2 where name like 'work%';
NAME VALUE
----------------------------------- ----------
workarea executions - optimal 12
workarea executions - onepass 0
workarea executions - multipass 0
why sort merge ?
non-equality joins
where t1.name > t2.name
hash joins
7.3
260
SQL> select value
2 from v$parameter
3 where name = 'hash_join_enabled';
VALUE
----------------------
true
261
"best" join
262
divide and conquer
263
demo
264
265
266
much larger hash
267
= and != only
268
nested loop
good selectivity into each table
small numbers of (result) rows
first row fast
269
hash join
the "best" join (theory)
270
sort merge
rarely seen
partial joins
271
272
back to our problem SQL
SQL> select e.department_id, sum(salary)
2 from emp e,
3 job_hist j
4 where e.employee_id = j.employee_id
5 and extract(year from e.hire_date) > 1985
6 and j.end_date > j.start_date + 1
7 and j.start_date >= e.hire_date
8 group by e.department_id
273
274
v$sql_plan
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 36M| 2742M| | 10998 (48)|
| 1 | HASH GROUP BY | | 36M| 2742M| | 10998 (48)|
|* 2 | HASH JOIN | | 36M| 2742M| 3728K| 9137 (37)|
|* 3 | TABLE ACCESS FULL| JOB_HIST | 88761 | 2687K| | 147 (3)|
|* 4 | TABLE ACCESS FULL| EMP | 877K| 40M| | 3028 (2)|
-----------------------------------------------------------------------------
275
276
now what ?
"where does it hurt ?"
277
278
279
where in the plan ...
SQL> select
2 DBMS_SQLTUNE.REPORT_SQL_MONITOR(
3 sql_id=>'d3ncuxj7629bf',
4 report_level=>'ALL',
5 type=>'HTML') as report
6 from dual;
280
options
284
rewrite the sql
hints
add indexes
remove indexes
rewrite the sql
285
ideally ... simply
286
287
dynamic sampling
288
cardinality is everything
288
289
290
291
same with Oracle
291
292
actual versus estimate
292
293
SQL> select /*+ GATHER_PLAN_STATISTICS */ count(*)
2 from VEHICLES
3 where MAKE = 'FORD'
4 and MODEL = 'FOCUS';
COUNT(*)
----------
214468
293
294
SQL> SELECT *
2 FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(
3 NULL, NULL, 'ALLSTATS LAST'));
-----------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |
|* 2 | TABLE ACCESS FULL| VEHICLES| 1 | 220K| 214K|
-----------------------------------------------------------------
294
295
295
if the estimate is wrong
296
296
try dynamic sampling
297
SQL> create table TOUGH_DATA as
2 select
3 rownum pk,
4 dbms_random.string('U',10) str
5 from dual
6 connect by level < 1000000
7 /
Table created.
SQL> exec dbms_stats.gather_table_stats(
user,'TOUGH_DATA')
298
SQL> select count(*)
2 from TOUGH_DATA
3 where str like '%XX'
4 /
COUNT(*)
----------
1452
hard
299
SQL> select count(*)
2 from TOUGH_DATA
3 where str like '%XX'
4 /
-------------------------------------------------
| Id | Operation | Name | Rows |
-------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | SORT AGGREGATE | | 1 |
|* 2 | TABLE ACCESS FULL| TOUGH_DATA | 50000 |
-------------------------------------------------
5% assumption
300
SQL> select /*+ dynamic_sampling(t 2) */ count(*)
2 from TOUGH_DATA t
3 where str like '%XX'
4 /
-------------------------------------------------
| Id | Operation | Name | Rows |
-------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | SORT AGGREGATE | | 1 |
|* 2 | TABLE ACCESS FULL| TOUGH_DATA | 1252 |
-------------------------------------------------
more drastic measures
301
use hints
302
303
"optimizer hints should only be
used with extreme care"
Maria Colgan, Oct 2012
Optimizer product manager
awesome hints
304
305
gather_plan_statistics
dynamic_sampling
monitor
qb_name
query blocks
306
C#
PL/SQL
307
no comments
308
309
"C# is self-documenting"
310
for (int i = 0; i < w.Count; ++i)
{
if (w[i].v > 0 && w[i].p > mddh)
{
m = Math.Max(m, w[i].d);
}
}
for (int i = 0; i < w.Count; ++i)
{
if (w[i].v > 0 && w[i].p > mddh)
{
w[i].d = m / w[i].d;
s += w[i].d;
}
}
311
query blocks =
self- documenting SQL
312
select emp.*
from emp,
( select trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
313
Id | Operation | Name |
----------------------------------------------|
0 | SELECT STATEMENT | |
1 | HASH JOIN | |
2 | TABLE ACCESS BY INDEX ROWID | EMP |
3 | NESTED LOOPS | |
4 | VIEW | |
5 | SORT GROUP BY | |
6 | TABLE ACCESS BY INDEX ROWID| EMP |
7 | INDEX FULL SCAN | E2 |
8 | INDEX RANGE SCAN | E1 |
9 | VIEW | |
10 | SORT GROUP BY | |
11 | TABLE ACCESS BY INDEX ROWID | EMP |
12 | INDEX RANGE SCAN | E2 |
314
select emp.*
from emp,
( select /*+ QB_NAME(YR_HIRE) */
trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select /*+ QB_NAME(AV_SAL) */
deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
315
Id | Operation | Name | Query Block
----------------------------------------------|--------------
0 | SELECT STATEMENT | |
1 | HASH JOIN | |
2 | TABLE ACCESS BY INDEX ROWID | EMP |
3 | NESTED LOOPS | |
4 | VIEW | |
5 | SORT GROUP BY | |
6 | TABLE ACCESS BY INDEX ROWID| EMP |
7 | INDEX FULL SCAN | E2 |
8 | INDEX RANGE SCAN | E1 |
9 | VIEW | |
10 | SORT GROUP BY | |
11 | TABLE ACCESS BY INDEX ROWID | EMP |
12 | INDEX RANGE SCAN | E2 |
SEL$1
SEL$1
AV_SAL
AV_SAL
AV_SAL
AV_SAL
SEL$1
YR_HIRE
YR_HIRE
YR_HIRE
YR_HIRE
316
assist with other hints
317
select
/*+ QB_NAME(top)
INDEX(@yr_hire emp (empno))
FULL(@av_sal emp) */
emp.*
from emp,
( select /*+ QB_NAME(YR_HIRE) */
trunc(hiredate,'YYYY'), max(empno) empno
from emp
where empno > 0
group by trunc(hiredate,'YYYY') ) x,
( select /*+ QB_NAME(AV_SAL) */
deptno, avg(sal)
from emp
group by deptno ) y
where x.empno = emp.empno
and y.deptno = emp.deptno
318
sidebar
319
320
select
/*+ QB_NAME(top)
INDEX(@yr_hire emp (empno))
FULL(@av_sal emp)
*/
INDEX(emp emp_ix)
cool hints
321
322
first_rows_n
all_rows
leading
cardinality
statement_queueing
opt_param
assisting optimizer
323
dangerous hints
324
everything else...
325
326
full
index
use_hash
use_nl
etc
suppressing the optimizer
327
undocumented hints
328
329
selectivity
no_trigger
an invalid hint
330
is a comment
331
332
SQL> select /*+ INDEX(accounts_pk) */
2 from ACCOUNTS
3 where ...
SQL> select /*+ INDEX(a) */
2 from ACCOUNTS
3 where ...
SQL> select /*+ INDEX(scott.accounts) */
2 from SCOTT.ACCOUNTS
3 where ...
SQL> select /* INDEX(A) */
2 from SCOTT.ACCOUNTS A
3 where ...
no error raised !
333
even if it IS valid ...
334
... the (in)famous ignore issue
335
336
SQL> select *
2 from emp e,
3 dept d
4 where e.deptno = d.deptno
5 and d.dname = 'SALES';
--------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 |
| 1 | MERGE JOIN | | 5 |
|* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 |
|* 4 | SORT JOIN | | 14 |
| 5 | TABLE ACCESS FULL | EMP | 14 |
--------------------------------------------------------
337
"I want a hash join"
338
SQL> select /*+ use_hash(d) */ *
2 from emp e,
3 dept d
4 where e.deptno = d.deptno
5 and d.dname = 'SALES';
--------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 |
| 1 | MERGE JOIN | | 5 |
|* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 |
|* 4 | SORT JOIN | | 14 |
| 5 | TABLE ACCESS FULL | EMP | 14 |
--------------------------------------------------------
339
/*+ use_hash(d) */
if joining into "d"...
use a hash join
we're not...
340
341
--------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 |
| 1 | MERGE JOIN | | 5 |
|* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 |
| 3 | INDEX FULL SCAN | PK_DEPT | 4 |
|* 4 | SORT JOIN | | 14 |
| 5 | TABLE ACCESS FULL | EMP | 14 |
--------------------------------------------------------
342
if joining into "d"...
we must be starting with "e"
343
SQL> select /*+ leading(e) use_hash(d) */ *
2 from emp e,
3 dept d
4 where e.deptno = d.deptno
5 and d.dname = 'SALES';
---------------------------------------------------
| Id | Operation | Name | Rows | Bytes |
---------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 285 |
|* 1 | HASH JOIN | | 5 | 285 |
| 2 | TABLE ACCESS FULL| EMP | 14 | 518 |
|* 3 | TABLE ACCESS FULL| DEPT | 1 | 20 |
---------------------------------------------------
not enough hints
344
345
"hints are like violence…
if they do not work, use more"
346
SQL> select /*+ leading(e d b) use_hash(d) use_hash(b) */ *
2 from emp e,
3 dept d,
4 bonus b
5 where e.deptno = d.deptno
6 and d.dname = 'SALES'
7 and e.ename = b.ename;
---------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
|* 1 | HASH JOIN | | 1 |
|* 2 | HASH JOIN | | 5 |
| 3 | TABLE ACCESS FULL| EMP | 14 |
|* 4 | TABLE ACCESS FULL| DEPT | 1 |
| 5 | TABLE ACCESS FULL | BONUS | 1 |
---------------------------------------------
347
SQL> select /*+ leading(e d b) use_hash(d) use_hash(b) */ *
2 from emp e,
3 dept d,
4 bonus b
5 where e.deptno = d.deptno
6 and d.dname = 'SALES'
7 and e.ename = b.ename;
---------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
|* 1 | HASH JOIN | | 1 |
| 2 | TABLE ACCESS FULL | BONUS | 1 |
|* 3 | HASH JOIN | | 5 |
| 4 | TABLE ACCESS FULL| EMP | 14 |
|* 5 | TABLE ACCESS FULL| DEPT | 1 |
---------------------------------------------
348
---------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
|* 1 | HASH JOIN | | 1 |
|* 2 | HASH JOIN | | 5 |
| 3 | TABLE ACCESS FULL| EMP | 14 |
|* 4 | TABLE ACCESS FULL| DEPT | 1 |
| 5 | TABLE ACCESS FULL | BONUS | 1 |
---------------------------------------------
---------------------------------------------
| Id | Operation | Name | Rows |
---------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
|* 1 | HASH JOIN | | 1 |
| 2 | TABLE ACCESS FULL | BONUS | 1 |
|* 3 | HASH JOIN | | 5 |
| 4 | TABLE ACCESS FULL| EMP | 14 |
|* 5 | TABLE ACCESS FULL| DEPT | 1 |
---------------------------------------------
join inputs
349
350
SQL> select /*+ leading(e d b)
2 use_hash(d)
3 use_hash(b)
4 no_swap_join_inputs(b)
5 */
6 *
7 from emp e,
8 dept d,
9 bonus b
10 where e.deptno = d.deptno
11 and d.dname = 'SALES'
12 and e.ename = b.ename;
problem ...
351
352
/*+ no_swap_join_inputs (b) */
option 1
353
fully specify hints
354
355
SQL> SELECT *
2 from table(dbms_xplan.display(.... ,
format=>'typical +OUTLINE))
/*+ BEGIN_OUTLINE_DATA
USE_HASH(@"SEL$1" "B"@"SEL$1")
USE_HASH(@"SEL$1" "D"@"SEL$1")
LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1" "B"@"SEL$1")
FULL(@"SEL$1" "B"@"SEL$1")
FULL(@"SEL$1" "D"@"SEL$1")
FULL(@"SEL$1" "E"@"SEL$1")
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
DB_VERSION('11.2.0.2')
OPTIMIZER_FEATURES_ENABLE('11.2.0.2')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/ Ack: M.Colgan
swap still possible !
option 2
356
sql baseline
357
just hints … better in 12c
358
add / remove indexes
359
side effects
360
361
structural change
"an index will fix it..."
362
363
SQL> select *
2 from SALES
3 where SALES_DATE > ...
364
365
SQL> create index SALES_IX
2 on SALES( SALES_DATE );
Index created.
366
SQL> explain plan for
2 select * from SALES
3 where sales_date > ...;
--------------------------------------------------------
| Id | Operation | Name | Rows |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 950 |
| 1 | TABLE ACCESS BY INDEX ROWID| SALES | 950 |
|* 2 | INDEX RANGE SCAN | SALES_IX | 950 |
--------------------------------------------------------
367
368
369
your query
370
everyone elses queries
371
real example
372
SQL> create table T
2 as select * from all_objects;
Table created.
SQL> create index OBJ_IX on T ( OBJECT_ID);
Index created.
SQL> analyze table T estimate statistics;
Table analyzed.
373
SQL> set autotrace traceonly explain
SQL> select * from T
2 where OWNER = 'SCOTT'
3 and created > sysdate - 1
4 /
---------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 546 | 281 (1)|
|* 1 | TABLE ACCESS FULL| T | 6 | 546 | 281 (1)|
---------------------------------------------------------------
374
“Can I index OWNER..”
375
SQL> create index NEW_IX on T ( owner);
Index created.
SQL> select * from T
2 where OWNER = 'SCOTT'
3 and created > sysdate - 1;
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 546 | 122 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| T | 6 | 546 | 122 (0)|
|* 2 | INDEX RANGE SCAN | NEW_IX | 4107 | | 10 (0)|
---------------------------------------------------------------------------
376
existing code ?
377
before the new index
378
SQL> set autotrace traceonly explain
SQL> select * from T
2 where OWNER = 'SYS'
3 and OBJECT_ID between 10 and 8000
4 /
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 462 | 42042 | 143 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 143 (0)|
|* 2 | INDEX RANGE SCAN | OBJ_IX | 7851 | | 20 (0)|
---------------------------------------------------------------------------
379
SQL> set autotrace traceonly stat
SQL> select * from T
2 where owner = 'SYS'
3 and object_id between 10 and 8000
4 /
4967 rows selected.
Statistics
-----------------------------------------------------
0 recursive calls
0 db block gets
784 consistent gets
15 physical reads
380
after the new index
381
SQL> select * from T
2 where owner = 'SYS'
3 and object_id between 10 and 8000
4 /
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 462 | 42042 | 122 (0)|
|* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 122 (0)|
|* 2 | INDEX RANGE SCAN | NEW_IX | 4105 | | 10 (0)|
---------------------------------------------------------------------------
changed !
382
SQL> set autotrace traceonly stat
SQL> select * from T
2 where owner = 'SYS'
3 and object_id between 10 and 8000
4 /
4967 rows selected.
Statistics
------------------------------------------------------
0 recursive calls
0 db block gets
1522 consistent gets
62 physical reads
383
invisible indexesconsider
384
SQL> alter index OWN_IX invisible;
Index altered.
385
SQL> alter session set
2 optimizer_use_invisible_indexes = true;
Session altered.
SQL> [MY QUERY]
SQL> alter session set
2 optimizer_use_invisible_indexes = false;
Session altered.
wrap up
386
if you are tuning SQL ...
387
... you are failing
tuning the user experience
388
389
find
stop
side effects
cure
390
ORA-03113
connormcdonald.wordpress.com

SQL Tuning 101 - Sep 2013

  • 1.
  • 2.
  • 4.
  • 5.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
    11 Dump of memoryfrom 0x07246400 to 0x07248400 1064B4C00 06A20000 08C0000A 0A07C47E 00020506 [...........~....] 1064B4C10 34BC0000 01000000 00030CBF 0A07C47C [4..............|] 1064B4C20 0002EC28 00020300 00000000 0004001D [...(............] ... 1064B6BF0 C10B02C1 0B06436F 6E6E6F72 C47E0605 [......Connor.~..] table or index block size database version created in relative block address
  • 12.
  • 13.
  • 14.
  • 15.
    if you aretuning SQL ... 15
  • 16.
    ... you arefailing 16
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
    "it’s a SQLproblem" 25
  • 26.
    26 SQL> desc ACCOUNT NameNull? Type ----------------------------------- -------- ------------------------ ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ... SQL> desc TRANSACTIONS Name Null? Type ----------------------------------- -------- ------------------- TXN_SEQ NOT NULL NUMBER(11) TXN_TS NOT NULL TIMESTAMP(6) TXN_TYPE NOT NULL VARCHAR2(10) ACCOUNT_NUM NOT NULL NUMBER(8) AMOUNT NOT NULL NUMBER(11,2)
  • 27.
  • 28.
    28 SQL> select ACCOUNT_NUM,max(TXN_TS) LAST_TS 2 from TRANSACTIONS, ACCOUNT 3 where <joins etc> 4 group by ACCOUNT_NUM 5 order by 1;
  • 29.
    29 SQL> select ACCOUNT_NUM,max(TXN_TS) LAST_TS 2 from TRANSACTIONS 3 group by ACCOUNT_NUM 4 order by 1; simplified
  • 30.
    30 SQL> select ACCOUNT_NUM,max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 group by ACCOUNT_NUM 4 order by 1; -------------------------------------------------- | Id | Operation | Name | -------------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | TABLE ACCESS FULL | TRANSACTIONS | --------------------------------------------------
  • 31.
  • 32.
    32 SQL> select /*+PARALLEL(t 16) */ 2 ACCOUNT_NUM, max(TXN_TS) LAST_TS 3 from TRANSACTIONS t 4 group by ACCOUNT_NUM 5 order by 1;
  • 33.
  • 34.
  • 35.
  • 36.
    36 create index TRANSACTIONS_IXon TRANSACTIONS ( account_num, txn_ts ) SQL> select ACCOUNT_NUM, max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 group by ACCOUNT_NUM 4 order by 1; -------------------------------------------------- | Id | Operation | Name | -------------------------------------------------- | 0 | SELECT STATEMENT | | | 1 | INDEX FAST FULL SCAN| TRANSACTIONS_IX | --------------------------------------------------
  • 37.
  • 38.
  • 39.
  • 40.
    40 CREATE TABLE TRANSACTIONS ( ... ) PARTITIONBY RANGE (TXN_TS) INTERVAL( NUMTOYMINTERVAL(1,'MONTH')) ( PARTITION P1 VALUES LESS THAN (TIMESTAMP' 2009-01-01 00:00:00') PARTITION P2 VALUES LESS THAN (TIMESTAMP' 2009-06-01 00:00:00') ... );
  • 41.
    41 SQL> select ACCOUNT_NUM,max(TXN_TS) LAST_TS 2 from TRANSACTIONS t 3 where TXN_TS > add_months(sysdate,-12) 4 group by ACCOUNT_NUM 5 order by 1;
  • 42.
    42 --------------------------------------------------------------- | Id |Operation | Name |Pstart| Pstop | -------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | | 1 | PARTITION RANGE ITER..| | 127 | 138 | |* 2 | TABLE ACCESS FULL | TRANSACTIONS | 127 | 138 | -------------------------------------------------------------
  • 43.
  • 44.
    ... changed thefunction 44
  • 45.
  • 47.
  • 48.
  • 49.
    49 SQL> insert intoGTT_LAST_TXN 2 select ACCOUNT_NUM, max(TXN_TS) LAST_TS 3 from TRANSACTIONS t 4 where TXN_TS >= trunc(sysdate,'MM') 5 group by ACCOUNT_NUM; for i in ( select ACCOUNT_NUM from ACCOUNTS minus select ACCOUNT_NUM from GTT_LAST_TXN ) insert into GTT_LAST_TXN select /*+ INDEX_DESC(t (account_num, txn_ts)) */ MAX(TXN_TS) from TRANSACTIONS t where ACCOUNT_NUM = i.ACCOUNT_NUM and TXN_TS < trunc(sysdate,'MM')
  • 50.
  • 51.
  • 52.
  • 53.
    53 SQL> select ... 2from ... 3 where ...
  • 54.
  • 55.
    55 "we have aninterest in recent activity for account holders" "last transaction for all accounts"
  • 56.
    promotional material 56 "we haven'tseen you in a while, here's a discount on ...."
  • 57.
  • 58.
  • 59.
  • 60.
    60 SQL> desc ACCOUNT NameNull? Type ----------------------------------- -------- --------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ... ... ... MODIFICATION_TS NOT NULL TIMESTAMP(6)
  • 61.
  • 62.
    62 select ..., MODIFICATION_TS into..., :prev_modtstamp from ACCOUNT where ... update ACCOUNT set ... where ACCOUNT_NUM = :b1 and MODIFICATION_TS = :prev_modtstamp if SQL%NOTFOUND then msg('Row has been changed by another user, please requery'); end if;
  • 63.
    63 SQL> select ACCOUNT_NUM, 2MODIFICATION_TS approx_last_usage 3 from ACCOUNT
  • 64.
  • 65.
  • 66.
    66 SQL> desc ACCOUNT NameNull? Type ------------------------------- -------- -------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) ...
  • 67.
    67 update ACCOUNT set ... whereACCOUNT_NUM = :b1 and MODIFICATION_TS = :prev_modtstamp LAST_TXN_TS = systimestamp LARGEST_TXN_AMT = greatest(TXN_AMT,LARGEST_TXN_AMT) BALANCE_CEILING = greatest(BALANCE,BALANCE_CEILING) BALANCE_FLOOR = least(BALANCE,BALANCE_FLOOR)
  • 68.
    68 SQL> desc ACCOUNT NameNull? Type ----------------------------------- -------- --------------- ACCOUNT_NUM NOT NULL NUMBER(8) CURRENT_BALANCE NOT NULL NUMBER(14,2) LAST_WITHDRAWAL_TS TIMESTAMP(6) LAST_DEPOSIT_TS TIMESTAMP(6) LAST_TXN_TS TIMESTAMP(6) LARGEST_TXN_AMT NUMBER(14,2) BALANCE_CEILING NUMBER(14,2) BALANCE_FLOOR NUMBER(14,2)
  • 69.
  • 70.
    (semi) automate 70 "we haven'tseen you in a while, here's a discount on ...."
  • 71.
    too focused onthe SQL 71
  • 72.
  • 73.
    if you don'ttune SQL ... 73
  • 74.
    ...what are youtuning ? 74
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
    all solutions shown... 84 denormalised indexes structure horse power
  • 85.
  • 86.
  • 87.
  • 88.
    tuning the userexperience 88
  • 89.
    SQL as ameans, not an end 89
  • 90.
  • 91.
    so if we're"failing"… 91
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
    104 constipation dizziness drowsiness headache lightheadedness nausea mood swingssweating vomitingrash itching difficulty breathing tightnessin the chest swelling of the mouth confusion disorientation fainting irregular heartbeat hallucinations seizures sudden chest pain unusual bruising or bleeding blurred vision
  • 105.
    "This is nota complete list" 105
  • 106.
    triage 106 find the (likely)pain stop the bleeding avoid side effects work toward cure
  • 107.
  • 108.
  • 109.
    where not toolook ... 109 (maybe)
  • 110.
  • 111.
    "server CPU is45%" 111 "buffer cache is 99%"
  • 112.
  • 113.
  • 114.
    "no problems last15 minutes" 114
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
    125 procedure MY_PROC(...) is begin dbms_application_info.set_module('MY_PROC'); dai.set_client_info('p_parm1 = '||p_parm1); dai.set_client_info(' p_parm2 = '||p_parm2); select ... update ... dai.set_action('now loading changes'); ... end;
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
    131 SQL> desc V$ACTIVE_SESSION_HISTORY NameNull? Type ------------------------------- -------- ------------------- SAMPLE_ID NUMBER SAMPLE_TIME TIMESTAMP(3) IS_AWR_SAMPLE VARCHAR2(1) SESSION_ID NUMBER SESSION_SERIAL# NUMBER SESSION_TYPE VARCHAR2(10) FLAGS NUMBER USER_ID NUMBER SQL_ID VARCHAR2(13) IS_SQLID_CURRENT VARCHAR2(1) SQL_CHILD_NUMBER NUMBER SQL_OPCODE NUMBER SQL_OPNAME VARCHAR2(64) FORCE_MATCHING_SIGNATURE NUMBER TOP_LEVEL_SQL_ID VARCHAR2(13) TOP_LEVEL_SQL_OPCODE NUMBER SQL_PLAN_HASH_VALUE NUMBER SQL_PLAN_LINE_ID NUMBER SQL_PLAN_OPERATION VARCHAR2(30)
  • 132.
    "This morning, myscreen froze for 3 mins running Pay Adjustment..." 132
  • 133.
    133 SQL> select sql_id, 2sql_exec_id, 3 count(*) 4 from v$active_session_history 5 where program = 'Finance.exe' 6 and module = 'PayAdjust' 7 and sample_time > timestamp '2013-08-20 08:00:00' 8 and sql_id is not null 9 group by 10 sql_id, 11 sql_exec_id 12 order by 3 desc ;
  • 134.
    134 SQL_ID SQL_EXEC_ID COUNT(*) ------------------------ ---------- 087jnbt3bg3fn 33562711 178 9n2nx15wj6tb3 33512732 39 7nvh5pd4y5nqu 33562791 36 7nvh5pd4y5nqu 33562735 30 7nvh5pd4y5nqu 33562736 29 6b5r2j5p2z7kk 33671666 14 6b5r2j5p2z7kk 33670545 12 7nvh5pd4y5nqu 33562689 11 bamffwpy8v8bt 33554432 9 ...
  • 135.
    135 # cd $ORACLE_HOME/rdbms/admin #sqlplus / as sysdba @ashrpt
  • 136.
  • 137.
  • 138.
    138 SQL> select sql_fulltext 2from v$sql 3 where sql_id = '087jnbt3bg3fn'; SQL_FULLTEXT ----------------------------------------------- SELECT ... FROM ...
  • 139.
  • 140.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
    you can dobetter 153
  • 154.
    154 SQL> select sql_fulltext 2from v$sqlstats 3 where sql_id = '087jnbt3bg3fn'; SQL_FULLTEXT ----------------------------------------------- SELECT ... FROM ...
  • 155.
    "The column definitionsfor columns in V$SQLSTATS are identical to those in the V$SQL and V$SQLAREA views. However, the V$SQLSTATS view differs from V$SQL and V$SQLAREA in that it is faster, more scalable, and has a greater data retention (the statistics may still appear in this view, even after the cursor has been aged out of the shared pool)." 155
  • 156.
  • 157.
    SQL> select e.department_id,sum(salary) 2 from emp e, 3 job_hist j 4 where e.employee_id = j.employee_id 5 and extract(year from e.hire_date) > 1985 6 and j.end_date > j.start_date + 1 7 and j.start_date >= e.hire_date 8 group by e.department_id 157
  • 158.
  • 159.
    optimizer got itwrong... 159
  • 160.
  • 161.
    ... it cannotrun better 161 legitimate response
  • 162.
    be like theoptimizer 162 only smarter
  • 163.
    what does itdo ? 163
  • 164.
  • 165.
  • 166.
  • 167.
    167 SQL> alter sessionset events = 2 '10053 trace name context forever, level 1'; Session altered. SQL> explain plan for 2 select e.empno, d.dname 3 from emp e, 4 dept d 5 where e.deptno = d.deptno 6 and e.ename like '%A%' 7 and d.deptno != 5; Explained.
  • 168.
    168 SQL> select p.tracefile 2from v$session s, v$process p 3 where s.paddr = p.addr 4 and s.sid = sys_context('USERENV','SID'); TRACEFILE ---------------------------------------------- /u01/app/oracle/diag/..../MYDB_ora_2994270.trc
  • 169.
    169 --------------------- QUERY BLOCK SIGNATURE --------------------- signature(): qb_name=SEL$1 nbfros=2 flg=0 fro(0): flg=4 objn=51562 hint_alias="D"@"SEL$1" fro(1): flg=4 objn=51564 hint_alias="E"@"SEL$1" ****************************************** ----- Current SQL Statement (sql_id=gvg2yvpdr4uaw) ----- explain plan for select e.empno, d.dname from emp e, dept d where e.deptno = d.deptno and e.ename like '%A%' and d.deptno != 5 *******************************************
  • 170.
    170 ****************************** PARAMETERS ****************************** Compilation Environment Dump optimizer_mode_hinted= false optimizer_features_hinted = 0.0.0 parallel_execution_enabled = true parallel_query_forced_dop = 0 parallel_dml_forced_dop = 0 parallel_ddl_forced_degree = 0 parallel_ddl_forced_instances = 0 _query_rewrite_fudge = 90 optimizer_features_enable = 11.2.0.2 _optimizer_search_limit = 5
  • 171.
    171 Considering Query Transformations ************************** ************************* CommonSubexpression elimination Order-by elimination Join Elimination ************************* SQL:******* UNPARSED QUERY IS ******* SELECT "E"."EMPNO" "EMPNO","D"."DNAME" "DNAME" FROM "SCOTT"."EMP" "E","SCOTT"."DEPT" "D" WHERE "E"."DEPTNO"="D"."DEPTNO" AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5
  • 172.
    172 Predicate Move-Around (PM) ************************** "E"."DEPTNO"="D"."DEPTNO"AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5 ... finally: "E"."DEPTNO"="D"."DEPTNO" AND "E"."ENAME" LIKE '%A%' AND "D"."DEPTNO"<>5 AND "E"."DEPTNO"<>5
  • 173.
    173 SINGLE TABLE ACCESSPATH Single Table Cardinality Estimation for EMP[E] Table: EMP Alias: E Card: Original: 14.000000 Rounded: 1 Computed: 0.70 Access Path: TableScan Cost: 4.00 Resp: 4.00 Degree: 0 Cost_io: 4.00 Cost_cpu: 41081 Resp_io: 4.00 Resp_cpu: 41081 Best:: AccessPath: TableScan Cost: 4.00 Degree: 1 Resp: 4.00 Card: 0.70 Bytes: 0
  • 174.
    174 Access path analysisfor DEPT *************************************** SINGLE TABLE ACCESS PATH Single Table Cardinality Estimation for DEPT[D] Using prorated density: 0.208333 of col #1 as selectvity of out-of-range/non-existent value pred Table: DEPT Alias: D Card: Original: 4.000000 Rounded: 3 Computed: 3.17 Access Path: TableScan Cost: 4.00 Resp: 4.00 Degree: 0 Cost_io: 4.00 Cost_cpu: 36467 Resp_io: 4.00 Resp_cpu: 36467 Best:: AccessPath: TableScan Cost: 4.00 Degree: 1 Resp: 4.00 Card: 3.17 Bytes: 0
  • 175.
    175 Join order[1]: EMP[E]#0DEPT[D]#1 *************** Now joining: DEPT[D]#1 *************** NL Join Outer table: Card: 0.70 Cost: 4.00 Resp: 4.00 Degree: 1 Bytes: 13 Access path analysis for DEPT Access Path: TableScan Access Path: index (UniqueScan) Index: PK_DEPT
  • 176.
    176 SM Join SM cost:10.01 Outer table: EMP Alias: E resc: 4.00 card 0.70 bytes: 13 deg: 1 resp: 4.00 Inner table: DEPT Alias: D resc: 4.00 card: 3.17 bytes: 13 deg: 1 resp: 4.00 HA Join HA cost: 8.51 resc: 8.51 resc_io: 8.00 resc_cpu: 4367998 resp: 8.51 resp_io: 8.00 resp_cpu: 4367998 Best:: JoinMethod: NestedLoop Cost: 5.01 Degree: 1 Resp: 5.01 Card: 0.55 Bytes: 26
  • 177.
    177 Join order[2]: DEPT[D]#1EMP[E]#0 *************** Now joining: EMP[E]#0 *************** NL Join ... SM Join ... HA Join ...
  • 178.
    178 ------------------------------------------------+---------------+ | Id |Operation | Name | Rows | Cost | ------------------------------------------------+---------------- | 0 | SELECT STATEMENT | | | 5 | | 1 | NESTED LOOPS | | | | | 2 | NESTED LOOPS | | 1 | 5 | | 3 | TABLE ACCESS FULL | EMP | 1 | 4 | | 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 0 | | 5 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 1 | ------------------------------------------------+---------------+
  • 179.
  • 180.
    can I writeit better ? 180 CONSIDERING QUERY TRANSFORMATIONS
  • 181.
    where should Istart ? 181 SINGLE TABLE ACCESS PATH
  • 182.
    what should Ijoin to (next) ? 182 Join order[1]: EMP[E]#0 DEPT[D]#1
  • 183.
    how should Ijoin ? 183 NL Join HA Join SM Join
  • 184.
    we follow itslead 184
  • 185.
    what is thereal query 185
  • 186.
    186 SQL> set autotracetraceonly stat SQL> select * from STUFF 2 where CREATED > sysdate Statistics ------------------------------------------ 651 recursive calls 0 db block gets 2243 consistent gets 24 physical reads
  • 187.
  • 188.
    188 SQL> variable cclob SQL> begin 2 dbms_utility.expand_sql_text 3 ( 'select * from STUFF '|| 4 'where created > sysdate',:c); 5 end; 6 / PL/SQL procedure successfully completed. SQL> print c
  • 189.
    189 SQL> create orreplace 2 view STUFF as 3 select 4 o.owner, 5 o.created, 6 s.bytes, 7 s.tablespace_name 8 from 9 dba_segments s, 10 all_objects o 11 where o.owner = s.owner 12 and o.object_name = s.segment_name; View created.
  • 190.
    190 SELECT "A1"."OWNER" "OWNER", "A1"."NAME""NAME", "A1"."CREATED" "CREATED", "A1"."BYTES" "BYTES", "A1"."TABLESPACE_NAME" "TABLESPACE_NAME" FROM (SELECT "A2"."OWNER" "OWNER", "A2"."OBJECT_NAME" "NAME", "A2"."CREATED" "CREATED", "A3"."BYTES" "BYTES", "A3"."TABLESPACE_NAME" "TABLESPACE_NAME" FROM (SELECT "A4" ."OWNER" "OWNER", "A4"."SEGMENT_NAME" "SEGMENT_NAME", "A4"."PARTITION_NAME" "PARTITION_NAME", "A4"."SEGMENT_TYPE" "SEGMENT_TYPE", "A4"."SEGMENT_SUBTYPE" "SEGMENT_SUBTYPE", "A4"."TABLESPACE_NAME" "TABLESPACE_NAME", "A4"."HEADER_FILE" "HEADER_FILE", "A4"."HEADER_BLOCK" "HEADER_BLOCK", DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO", "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."BLOCKS"), "A4"."BLOCKS"))*"A4"."BLOCKSIZE" "BYTES", DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_BLOCKS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO",
  • 191.
    191 "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."BLOCKS"), "A4"."BLOCKS")) "BLOCKS",DECODE(BITAND("A4"."SEGMENT_FLAGS",131072),131072, "A4"."EXTENTS",DECODE(BITAND("A4"."SEGMENT_FLAGS",1),1, "SYS"."DBMS_SPACE_ADMIN"."SEGMENT_NUMBER_EXTENTS"("A4"."TABLESPACE_ID", "A4"."RELATIVE_FNO", "A4"."HEADER_BLOCK", "A4"."SEGMENT_TYPE_ID", "A4"."BUFFER_POOL_ID", "A4"."SEGMENT_FLAGS", "A4"."SEGMENT_OBJD", "A4"."EXTENTS"), "A4"."EXTENTS")) "EXTENTS", "A4"."INITIAL_EXTENT""INITIAL_EXTENT", "A4"."NEXT_EXTENT" "NEXT_EXTENT", "A4"."MIN_EXTENTS" "MIN_EXTENTS", "A4"."MAX_EXTENTS" "MAX_EXTENTS", "A4"."MAX_SIZE" "MAX_SIZE", "A4"."RETENTION" "RETENTION", "A4"."MINRETENTION" "MINRETENTION", "A4"."PCT_INCREASE" "PCT_INCREASE", "A4"."FREELISTS" "FREELISTS", "A4"."FREELIST_GROUPS" "FREELIST_GROUPS", "A4"."RELATIVE_FNO" "RELATIVE_FNO", DECODE("A4"."BUFFER_POOL_ID",1,'KEEP',2,'RECYCLE','DEFAULT') "BUFFER_POOL", DECODE("A4"."FLASH_CACHE",1,'KEEP',2, 'NONE','DEFAULT') "FLASH_CACHE",DECODE("A4"."CELL_FLASH_CACHE",1,'KEEP',2,'NONE','DEFAULT') "CELL_FLASH_CACHE" FROM ( (SELECT NVL("A199"."NAME",'SYS') "OWNER", "A198"."NAME" "SEGMENT_NAME",
  • 192.
    192 "A198"."SUBNAME" "PARTITION_NAME", "A196"."OBJECT_TYPE" "SEGMENT_TYPE", "A195"."TYPE#""SEGMENT_TYPE_ID",DECODE(BIT AND("A195"."SPARE1",2097408),2097152,'SECUREFILE',256,'ASSM','MSSM') "SEGMENT_SUBTYPE", "A197"."TS#" "TABLESPACE_ID", "A197"."NAME" "TABLESPACE_NAME", "A197"."BLOCKSIZE" "BLOCKSIZE", "A194"."FILE#" "HEADER_FILE", "A195"."BLOCK#" "HEADER_BLOCK", "A195"."BLOCKS"*"A197"."BLOCKSIZE" "BYTES", "A195"."BLOCKS" "BLOCKS", "A195"."EXTENTS" "EXTENTS", "A195"."INIEXTS"*"A197"."BLOCKSIZE" "INITIAL_EXTENT", "A195"."EXTSIZE"*"A197"."BLOCKSIZE" "NEXT_EXTENT", "A195"."MINEXTS" "MIN_EXTENTS", "A195"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A195"."SPARE1",4194304),4194304, "A195"."BITMAPRANGES",NULL) "MAX_SIZE",TO_CHAR(DECODE( BITAND("A195"."SPARE1",2097152),2097152, DECODE("A195"."LISTS",0,'NONE',1,'AUTO',2,'MIN',3,'MAX',4,'DEFAULT','INVALID'),NULL)) "RETENTION",DECODE(BITAND("A195"."SPARE1",2097152),2097152, "A195"."GROUPS",NULL) "MINRETENTION",DECODE(BITAND("A197"."FLAGS",3),1,TO_NUMBER(NULL), "A195"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A197"."FLAGS",32),32, TO_NUMBER(NULL),DECODE("A195"."LISTS",0,1, "A195"."LISTS")) "FREELISTS",DECODE(BITAND("A197"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A195"."GROUPS",0,1, "A195"."GROUPS")) "FREELIST_GROUPS", "A195"."FILE#" "RELATIVE_FNO",BITAND("A195"."CACHEHINT",3) "BUFFER_POOL_ID", BITAND("A195"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A195"."CACHEHINT",48)/16 "CELL_FLASH_CACHE", NVL("A195"."SPARE1",0) "SEGMENT_FLAGS",DECODE(BITAND("A195"."SPARE1",1),1, "A195"."HWMINCR", "A198"."DATAOBJ#") "SEGMENT_OBJD" FROM "SYS"."USER$" "A199", "SYS"."OBJ$" "A198", "SYS"."TS$" "A197", ( (SELECT
  • 193.
    193 DECODE(BITAND("A209"."PROPERTY",8192),8192,'NESTED TABLE','TABLE') "OBJECT_TYPE", 2"OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A209"."OBJ#" "OBJECT_ID", "A209"."FILE#" "HEADER_FILE", "A209"."BLOCK#" "HEADER_BLOCK", "A209"."TS#" "TS_NUMBER" FROM "SYS"."TAB$" "A209" WHERE BITAND("A209"."PROPERTY",1024)=0) UNI ON ALL (SELECT 'TABLE PARTITION' "OBJECT_TYPE",19 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A208"."OBJ#" "OBJECT_ID", "A208"."FILE#" "HEADER_FILE", "A208"."BLOCK#" "HEADER_BLOCK", "A208"."TS#" "TS_NUMBER" FROM "SYS"."TABPART$" "A208") UNION ALL (SELECT 'CLUSTER' "OBJECT_TYPE",3 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A207"."OBJ#" "OBJECT_ID", "A207"."FILE#" "HEADER_FILE", "A207"."BLOCK#" "HEADER_BLOCK", "A207"."TS#" "TS_NUMBER" FROM "SYS"."CLU$" "A207") UNION ALL (SELECT DECODE("A206"."TYPE#",8,'LOBINDEX','INDEX') "OBJECT_TYPE",1 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A206"."OBJ#" "OBJECT_ID", "A206"."FILE#" "HEADER_FILE", "A206"."BLOCK#" "HEADER_BLOCK", "A206"."TS#" "TS_NUMBER" FROM "SYS"."IND$" "A206" WHERE "A206"."TYPE#"=1 OR "A206"."TYPE#"=2 OR "A206"."TYPE#"=3 OR "A206"."TYPE#"=4 OR "A206"."TYPE#"=6 OR "A206"."TYPE#"=7 OR "A206"."TYPE#"=8 OR "A206"."TYPE#"=9) UNION ALL (SELECT 'INDEX PARTITION' "OBJECT_TYPE",20 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A205"."OBJ#" "OBJECT_ID", "A205"."FILE#" "HEADER_FILE", "A205"."BLOCK#" "HEADER_BLOCK",
  • 194.
    194 "A205"."TS#" "TS_NUMBER" FROM"SYS"."INDPART$" "A205") UNION ALL (SELECT 'LOBSEGMENT' "OBJECT_TYPE",21 "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID", "A204"."LOBJ#" "OBJECT_ID", "A204"."FILE#" "HEADER_FILE", "A204"."BLOCK#" "HEADER_BLOCK", "A204"."TS#" "TS_NUMBER" FROM "SYS"."LOB$" "A204" WHERE BITAND("A204"."PROPERTY",64)=0 OR BITAND("A204"."PROPERTY",128)=128) UNION ALL (SELECT 'TABLE SUBPARTITION' "OBJECT_TYPE",34 "OBJECT_TYPE_ID",5 "SEGMENT_TYPE_ID", "A203"."OBJ#" "OBJECT_ID", "A203"."FILE#" "HEADER_FILE", "A203"."BLOCK#" "HEADER_BLOCK", "A203"."TS#" "TS_NUMBER" FROM "SYS"."TABSUBPART$" "A203") UNION ALL (SELECT 'INDEX SUBPARTITION' "OBJECT_TYPE",35 "OBJECT_TYPE_ID",6 "SEGMENT_TYPE_ID", "A202"."OBJ#" "OBJECT_ID", "A202"."FILE#" "HEADER_FILE", "A202"."BLOCK#" "HEADER_BLOCK", "A202"."TS#" "TS_NUMBER" FROM "SYS"."INDSUBPART$" "A202") UNION ALL (SELECT DECODE("A201"."FRAGTYPE$",'P','LOB PARTITION','LOB SUBPARTITION') "OBJECT_TYPE",DECODE("A201"."FRAGTYPE$",'P',40,41) "OBJECT_TYPE_ID",8 "SEGMENT_TYPE_ID", "A201"."FRAGOBJ#" "OBJECT_ID", "A201"."FILE#" "HEADER_FILE", "A201"."BLOCK#" "HEADER_BLOCK", "A201"."TS#" "TS_NUMBER" FROM "SYS"."LOBFRAG$" "A201")) "A196", "SYS"."SEG$" "A195", "SYS"."FILE$" "A194" WHERE "A195"."FILE#"="A196"."HEADER_FILE" AND "A195"."BLOCK#"="A196"."HEADER_BLOCK" AND "A195"."TS#"="A196"."TS_NUMBER" AND "A195"."TS#"="A197"."TS#" AND "A198"."OBJ#"="A196"."OBJECT_ID" AND "A198"."OWNER#"="A199"."USER#"(+) AND "A195"."TYPE#"="A196"."SEGMENT_TYPE_ID" AND "A198"."TYPE#"="A196"."OBJECT_TYPE_ID" AND "A195"."TS#"="A194"."TS#" AND
  • 195.
    195 "A195"."FILE#"="A194"."RELFILE#") UNION ALL (SELECTNVL("A193"."NAME",'SYS') "OWNER", "A191"."NAME" "SEGMENT_NAME",NULL "PARTITION_NAME", DECODE("A190"."TYPE#",1,'ROLLBACK',10,'TYPE2 UNDO') "SEGMENT_TYPE", "A190"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A192"."TS#" "TABLESPACE_ID", "A192"."NAME" "TABLESPACE_NAME", "A192"."BLOCKSIZE" "BLOCKSIZE", "A189"."FILE#" "HEADER_FILE", "A190"."BLOCK#" "HEADER_BLOCK", "A190"."BLOCKS"*"A192"."BLOCKSIZE" "BYTES", "A190"."BLOCKS" "BLOCKS", "A190"."EXTENTS" "EXTENTS", "A190"."INIEXTS"*"A192"."BLOCKSIZE" "INITIAL_EXTENT", "A190"."EXTSIZE"*"A192"."BLOCKSIZE" "NEXT_EXTENT", "A190"."MINEXTS" "MIN_EXTENTS", "A190"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A190"."SPARE1",4194304),4194304, "A190"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION", "A190"."EXTPCT" "PCT_INCREASE",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A190"."LISTS",0,1, "A190"."LISTS")) "FREELISTS",DECODE(BITAND("A192"."FLAGS",32),32,TO_NUMBER(NULL), DECODE("A190"."GROUPS",0,1,"A190"."GROUPS")) "FREELIST_GROUPS", "A190"."FILE#" "RELATIVE_FNO",BITAND("A190"."CACHEHINT",3) "BUFFER_POOL_ID",BITAND("A190"."CACHEHINT",12)/4 "FLASH_CACHE", BITAND("A190"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A190"."SPARE1",0) "SEGMENT_FLAGS", "A191"."US#" "SEGMENT_OBJD" FROM "SYS"."USER$" "A193","SYS"."TS$" "A192", "SYS"."UNDO$" "A191", "SYS"."SEG$" "A190", "SYS"."FILE$" "A189" WHERE "A190"."FILE#"="A191"."FILE#" AND "A190"."BLOCK#"="A191"."BLOCK#" AND "A190"."TS#"="A191"."TS#" AND "A190"."TS#"="A192"."TS#" AND "A190"."USER#"="A193"."USER#"(+) AND ("A190"."TYPE#"=1 OR "A190"."TYPE#"=10) AND "A191"."STATUS$"<>1 AND
  • 196.
    196 "A191"."TS#"="A189"."TS#" AND "A191"."FILE#"="A189"."RELFILE#") UNIONALL (SELECT NVL("A188"."NAME",'SYS') "OWNER", TO_CHAR("A185"."FILE#")||'.'||TO_CHAR("A186"."BLOCK#") "SEGMENT_NAME",NULL "PARTITION_NAME", DECODE("A186"."TYPE#",2,'DEFERRED ROLLBACK',3, 'TEMPORARY',4,'CACHE',9,'SPACE HEADER','UNDEFINED') "SEGMENT_TYPE", "A186"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A187"."TS#" "TABLESPACE_ID", "A187"."NAME" "TABLESPACE_NAME", "A187"."BLOCKSIZE" "BLOCKSIZE", "A185"."FILE#" "HEADER_FILE", "A186"."BLOCK#" "HEADER_BLOCK", "A186"."BLOCKS"*"A187"."BLOCKSIZE" "BYTES", "A186"."BLOCKS" "BLOCKS", "A186"."EXTENTS" "EXTENTS", "A186"."INIEXTS"*"A187"."BLOCKSIZE" "INITIAL_EXTENT", "A186"."EXTSIZE"*"A187"."BLOCKSIZE" "NEXT_EXTENT", "A186"."MINEXTS" "MIN_EXTENTS", "A186"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A186"."SPARE1",4194304),4194304, "A186"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION",DECODE(BITAND("A187"."FLAGS",3),1,TO_NUMBER(NULL), "A186"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."LISTS",0,1, "A186"."LISTS")) "FREELISTS",DECODE(BITAND("A187"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A186"."GROUPS",0,1, "A186"."GROUPS")) "FREELIST_GROUPS", "A186"."FILE#" "RELATIVE_FNO",BITAND("A186"."CACHEHINT",3) "BUFFER_POOL_ID",BITAND("A186"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A186"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A186"."SPARE1",0) "SEGMENT_FLAGS", "A186"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$" "A188", "SYS"."TS$" "A187", "SYS"."SEG$" "A186", "SYS"."FILE$" "A185" WHERE "A186"."TS#"="A187"."TS#" AND "A186"."USER#"="A188"."USER#"(+) AND "A186"."TYPE#"<>1 AND "A186"."TYPE#"<>5 AND
  • 197.
    197 "A186"."TYPE#"<>6 AND "A186"."TYPE#"<>8 AND "A186"."TYPE#"<>10AND "A186"."TYPE#"<>11 AND "A186"."TS#"="A185"."TS#" AND "A186"."FILE#"="A185"."RELFILE#") UNION ALL (SELECT NVL("A184"."NAME",'SYS') "OWNER",'HEATMAP' "SEGMENT_NAME", NULL "PARTITION_NAME",'SYSTEM STATISTICS' "SEGMENT_TYPE", "A182"."TYPE#" "SEGMENT_TYPE_ID",NULL "SEGMENT_SUBTYPE", "A183"."TS#" "TABLESPACE_ID", "A183"."NAME" "TABLESPACE_NAME", "A183"."BLO CKSIZE" "BLOCKSIZE", "A181"."FILE#" "HEADER_FILE", "A182"."BLOCK#" "HEADER_BLOCK", "A182"."BLOCKS"*"A183"."BLOCKSIZE" "BYTES", "A182"."BLOCKS" "BLOCKS", "A182"."EXTENTS" "EXTENTS", "A182"."INIEXTS"*"A183"."BLOCKSIZE" "INITIAL_EXTENT", "A182"."EXTSIZE"*"A183"."BLOCKSIZE" "NEXT_EXTENT", "A182"."MINEXTS" "MIN_EXTENTS", "A182"."MAXEXTS" "MAX_EXTENTS",DECODE(BITAND("A182"."SPARE1",4194304),4194304, "A182"."BITMAPRANGES",NULL) "MAX_SIZE",NULL "RETENTION",NULL "MINRETENTION",DECODE(BITAND("A183"."FLAGS",3),1,TO_NUMBER(NULL), "A182"."EXTPCT") "PCT_INCREASE",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DEC ODE("A182"."LISTS",0,1, "A182"."LISTS")) "FREELISTS",DECODE(BITAND("A183"."FLAGS",32),32,TO_NUMBER(NULL),DECODE("A182"."GROUPS",0,1, "A182"."GROUPS")) "FREELIST_GROUPS", "A182"."FILE#" "RELATIVE_FNO",BITAND("A182"."CACHEHINT",3) "BUFFER_POOL_ID", BITAND("A182"."CACHEHINT",12)/4 "FLASH_CACHE",BITAND("A18 2"."CACHEHINT",48)/16 "CELL_FLASH_CACHE",NVL("A182"."SPARE1",0) "SEGMENT_FLAGS", "A182"."HWMINCR" "SEGMENT_OBJD" FROM "SYS"."USER$" "A184",
  • 198.
    198 "SYS"."TS$" "A183", "SYS"."SEG$" "A182", "SYS"."FILE$""A181" WHERE "A182"."TS#"="A183"."TS#" AND "A182"."USER#"="A184"."USER#"(+) AND "A182"."TYPE#"=11 AND "A182"."TS#"="A181"."TS#" AND "A182"."FILE#"="A181"."RELFILE#")) "A4") "A3", (SELECT "A5"."NAME" "OWNER", "A6"."NAME" "OBJECT_NAME", "A6"."SUBNAME" "SUBOBJECT_NAME", "A6"."OBJ#" "OBJECT_ID", "A6"."DATAOBJ#" "DATA_OBJECT_ID",DECODE("A6"."TYPE#",0,'NEXT OBJECT',1,'INDEX', 2,'TABLE',3,'CLUSTER',4,'VIEW',5,'SYNONYM ',6,'SEQUENCE',7,'PROCEDURE',8,'FUNCTION',9,'PACKAGE',11,'PACKAGE BODY',12, 'TRIGGER',13,'TYPE',14,'TYPE BODY',19,'TABLE PARTITION',20,'INDEX PARTITION', 21,'LOB',22,'LIBRARY',23,'DIRECTORY',24,'QUEUE',28,'JAVA SOURCE',29,'JAVA CLASS',30, 'JAVA RESOURCE',32,'INDEXTYPE',33,'OPERATOR',34, 'TABLE SUBPARTITION',35,'INDEX SUBPARTITION',40,'LOB PARTITION',41,'LOB SUBPARTITION',42 ,NVL( (SELECT 'REWRITE EQUIVALENCE' "'REWRITEEQUIVALENCE'" FROM SYS."SUM$" "A52" WHERE "A52"."OBJ#"="A6"."OBJ#" AND BITAND("A52"."XPFLAGS",8388608)=8388608),'MATERIALIZED VIEW'),43,'DIMENSION', 44,'CONTEXT',46,'RULE SET',47,'RESOURCE PLAN',48,'CONSUMER GROUP',55,'XML SCHEMA',56,'JAVA DATA',57,'EDITION',59,'RULE', 60,'CAPTURE',61,'APPLY',62,'EVALUATION CONTEXT',66,'JOB',67,'PROGRAM',68,'JOB CLASS',69, 'WINDOW',72,'SCHEDULER GROUP',74,'SCHEDULE',79,'CHAIN',81,'FILE GROUP',82,'MINING MODEL',87,'ASSEMBLY',90,'CREDENTIAL',92,'CUBE DIMENSION',93,'CUBE',94,'MEASURE FOLDER',95,'CUBE BUILD PROCESS',100,'FILE WATCHER', 101,'DESTINATION',114,'SQL TRANSLATION PROFILE',115,'UNIFIED AUDIT POLICY','UNDEFINED') "OBJECT_TYPE", "A6"."CTIME" "CREATED", "A6"."MTIME" "LAST_DDL_TIME",TO_CHAR("A6"."STIME",'YYYY-MM-DD:HH24:MI:SS') "TIMESTAMP",DEC ODE("A6"."STATUS",0,'N/A',1,'VALID','INVALID') "STATUS",DECODE(BITAND("A6"."FLAGS",2),0,'N',2,'Y','N') "TEMPORARY",DECODE(BITAND("A6"."FLAGS",4),0,'N',4,'Y','N') "GENERATED",DECODE(BITAND("A6"."FLAGS",16),0,'N',16,'Y','N') "SECONDARY", "A6"."NAMESPACE" "NAMESPACE", "A6"."DEFINING_EDITION" "EDITION_NAM E",DECODE(BITAND("A6"."FLAGS",196608),65536,'METADATA LINK',131072,'OBJECT LINK','NONE') "SHARING", CASE WHEN ("A6"."TYPE#"=4 OR "A6"."TYPE#"=5 OR
  • 199.
  • 200.
  • 201.
    should I usean index ? 201
  • 202.
  • 203.
    203 SQL> select * 2from STUDENT 3 where gender = 'W';
  • 204.
    full scan (dba_extents) File 1,Block 271, 512 blocks File 2, Block 234, 256 blocks etc
  • 205.
    indexed access W, File1, Block 37, Row 4 W, File 1, Block 437, Row 11 Sue Jane POOL_IX (POOL_TYPE) STUDENT
  • 206.
    what will afull scan cost ? 206
  • 207.
    207 SQL> select blocks 2from dba_tables 3 where owner = 'SCOTT' 4 and table_name = 'STUDENT'; BLOCKS ---------- 9083
  • 208.
  • 209.
    209 SQL> select value 2from v$parameter 3 where name = 'db_file_multiblock_read_count'; VALUE --------------- 128
  • 210.
    IO cost blocks/ blocks at a time 210
  • 211.
  • 212.
    adj = 1.6765x orig0.6581 212 Ack: Wolfgang Brietling, 2001
  • 213.
  • 214.
    214 SQL> set autotracetraceonly explain SQL> select /*+ no_cpu_costing */ * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 224 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 | ----------------------------------------------------- 9083 / 41 = 221
  • 215.
    215 SQL> set autotracetraceonly explain SQL> select /*+ no_cpu_costing */ * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 224 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 224 | ----------------------------------------------------- 9083 / 41 = 221
  • 216.
  • 217.
  • 218.
    218 SQL> set autotracetraceonly explain SQL> select * from STUDENT; ----------------------------------------------------- | Id | Operation | Name | Rows | Cost | ----------------------------------------------------- | 0 | SELECT STATEMENT | | 531K| 1586 | | 1 | TABLE ACCESS FULL| STUDENT | 531K| 1586 | -----------------------------------------------------
  • 219.
    what will aindex scan cost ? 219
  • 220.
  • 221.
    221 SQL> select AVG_LEAF_BLOCKS_PER_KEY 2from USER_INDEXES 3 where INDEX_NAME = 'STUDENT_IX' AVG_LEAF_BLOCKS_PER_KEY ----------------------- 6
  • 222.
  • 223.
  • 224.
    run a few... validuse of hints
  • 225.
  • 226.
    nested loops hash sort merge indexjoin and-equal btree-bitmap conversion bitmap join
  • 227.
  • 228.
  • 229.
    "for each rowin outer, check for row in inner"
  • 230.
    for (i=1; i<100;i++) for (j=1; j<100; j++) for (k=1; k<100; k++) ... ...
  • 231.
  • 235.
  • 236.
    effort = L1+ M * L2 = cost to Lookup rows in outer table number of rows Matching criteria in outer table cost of Lookup matching row in inner table
  • 237.
    High M ...no good effort = L1 + M * L2 =
  • 238.
    High L2 ...no good effort = L1 + M * L2 =
  • 239.
    High L1 ...no good maybe effort = L1 + M * L2
  • 240.
  • 241.
  • 245.
  • 247.
  • 248.
    effort = S1+ S2 + M sort table 1 (hold result) sort table 2 (hold result) merge results (not held*)
  • 249.
  • 250.
    RAM SQL> select value* 0.05 / 1024 sort_kb 2 from v$parameter 3 where name = 'pga_aggregate_target'; SORT_KB ---------- 2457.6
  • 251.
  • 252.
  • 253.
  • 254.
  • 255.
    SQL> select *from v$mystat / v$sesstat / v$sysstat 2 where name like 'work%'; NAME VALUE ----------------------------------- ---------- workarea executions - optimal 12 workarea executions - onepass 0 workarea executions - multipass 0
  • 256.
  • 257.
  • 258.
  • 259.
  • 260.
    260 SQL> select value 2from v$parameter 3 where name = 'hash_join_enabled'; VALUE ---------------------- true
  • 261.
  • 262.
  • 263.
  • 264.
  • 265.
  • 266.
  • 267.
  • 268.
    = and !=only 268
  • 269.
    nested loop good selectivityinto each table small numbers of (result) rows first row fast 269
  • 270.
    hash join the "best"join (theory) 270
  • 271.
  • 272.
    272 back to ourproblem SQL
  • 273.
    SQL> select e.department_id,sum(salary) 2 from emp e, 3 job_hist j 4 where e.employee_id = j.employee_id 5 and extract(year from e.hire_date) > 1985 6 and j.end_date > j.start_date + 1 7 and j.start_date >= e.hire_date 8 group by e.department_id 273
  • 274.
  • 275.
    ----------------------------------------------------------------------------- | Id |Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 36M| 2742M| | 10998 (48)| | 1 | HASH GROUP BY | | 36M| 2742M| | 10998 (48)| |* 2 | HASH JOIN | | 36M| 2742M| 3728K| 9137 (37)| |* 3 | TABLE ACCESS FULL| JOB_HIST | 88761 | 2687K| | 147 (3)| |* 4 | TABLE ACCESS FULL| EMP | 877K| 40M| | 3028 (2)| ----------------------------------------------------------------------------- 275
  • 276.
  • 277.
    "where does ithurt ?" 277
  • 278.
  • 279.
  • 280.
    SQL> select 2 DBMS_SQLTUNE.REPORT_SQL_MONITOR( 3sql_id=>'d3ncuxj7629bf', 4 report_level=>'ALL', 5 type=>'HTML') as report 6 from dual; 280
  • 284.
  • 285.
  • 286.
  • 287.
  • 288.
  • 289.
  • 290.
  • 291.
  • 292.
  • 293.
    293 SQL> select /*+GATHER_PLAN_STATISTICS */ count(*) 2 from VEHICLES 3 where MAKE = 'FORD' 4 and MODEL = 'FOCUS'; COUNT(*) ---------- 214468 293
  • 294.
    294 SQL> SELECT * 2FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR( 3 NULL, NULL, 'ALLSTATS LAST')); ----------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | ----------------------------------------------------------------- | 1 | SORT AGGREGATE | | 1 | 1 | 1 | |* 2 | TABLE ACCESS FULL| VEHICLES| 1 | 220K| 214K| ----------------------------------------------------------------- 294
  • 295.
  • 296.
  • 297.
    297 SQL> create tableTOUGH_DATA as 2 select 3 rownum pk, 4 dbms_random.string('U',10) str 5 from dual 6 connect by level < 1000000 7 / Table created. SQL> exec dbms_stats.gather_table_stats( user,'TOUGH_DATA')
  • 298.
    298 SQL> select count(*) 2from TOUGH_DATA 3 where str like '%XX' 4 / COUNT(*) ---------- 1452 hard
  • 299.
    299 SQL> select count(*) 2from TOUGH_DATA 3 where str like '%XX' 4 / ------------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL| TOUGH_DATA | 50000 | ------------------------------------------------- 5% assumption
  • 300.
    300 SQL> select /*+dynamic_sampling(t 2) */ count(*) 2 from TOUGH_DATA t 3 where str like '%XX' 4 / ------------------------------------------------- | Id | Operation | Name | Rows | ------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 1 | SORT AGGREGATE | | 1 | |* 2 | TABLE ACCESS FULL| TOUGH_DATA | 1252 | -------------------------------------------------
  • 301.
  • 302.
  • 303.
    303 "optimizer hints shouldonly be used with extreme care" Maria Colgan, Oct 2012 Optimizer product manager
  • 304.
  • 305.
  • 306.
  • 307.
  • 308.
  • 309.
  • 310.
  • 311.
    for (int i= 0; i < w.Count; ++i) { if (w[i].v > 0 && w[i].p > mddh) { m = Math.Max(m, w[i].d); } } for (int i = 0; i < w.Count; ++i) { if (w[i].v > 0 && w[i].p > mddh) { w[i].d = m / w[i].d; s += w[i].d; } } 311
  • 312.
    query blocks = self-documenting SQL 312
  • 313.
    select emp.* from emp, (select trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 313
  • 314.
    Id | Operation| Name | ----------------------------------------------| 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 | 314
  • 315.
    select emp.* from emp, (select /*+ QB_NAME(YR_HIRE) */ trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select /*+ QB_NAME(AV_SAL) */ deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 315
  • 316.
    Id | Operation| Name | Query Block ----------------------------------------------|-------------- 0 | SELECT STATEMENT | | 1 | HASH JOIN | | 2 | TABLE ACCESS BY INDEX ROWID | EMP | 3 | NESTED LOOPS | | 4 | VIEW | | 5 | SORT GROUP BY | | 6 | TABLE ACCESS BY INDEX ROWID| EMP | 7 | INDEX FULL SCAN | E2 | 8 | INDEX RANGE SCAN | E1 | 9 | VIEW | | 10 | SORT GROUP BY | | 11 | TABLE ACCESS BY INDEX ROWID | EMP | 12 | INDEX RANGE SCAN | E2 | SEL$1 SEL$1 AV_SAL AV_SAL AV_SAL AV_SAL SEL$1 YR_HIRE YR_HIRE YR_HIRE YR_HIRE 316
  • 317.
  • 318.
    select /*+ QB_NAME(top) INDEX(@yr_hire emp(empno)) FULL(@av_sal emp) */ emp.* from emp, ( select /*+ QB_NAME(YR_HIRE) */ trunc(hiredate,'YYYY'), max(empno) empno from emp where empno > 0 group by trunc(hiredate,'YYYY') ) x, ( select /*+ QB_NAME(AV_SAL) */ deptno, avg(sal) from emp group by deptno ) y where x.empno = emp.empno and y.deptno = emp.deptno 318
  • 319.
  • 320.
    320 select /*+ QB_NAME(top) INDEX(@yr_hire emp(empno)) FULL(@av_sal emp) */ INDEX(emp emp_ix)
  • 321.
  • 322.
  • 323.
  • 324.
  • 325.
  • 326.
  • 327.
  • 328.
  • 329.
  • 330.
  • 331.
  • 332.
    332 SQL> select /*+INDEX(accounts_pk) */ 2 from ACCOUNTS 3 where ... SQL> select /*+ INDEX(a) */ 2 from ACCOUNTS 3 where ... SQL> select /*+ INDEX(scott.accounts) */ 2 from SCOTT.ACCOUNTS 3 where ... SQL> select /* INDEX(A) */ 2 from SCOTT.ACCOUNTS A 3 where ...
  • 333.
  • 334.
    even if itIS valid ... 334
  • 335.
    ... the (in)famousignore issue 335
  • 336.
    336 SQL> select * 2from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  • 337.
    337 "I want ahash join"
  • 338.
    338 SQL> select /*+use_hash(d) */ * 2 from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  • 339.
    339 /*+ use_hash(d) */ ifjoining into "d"... use a hash join
  • 340.
  • 341.
    341 -------------------------------------------------------- | Id |Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 1 | MERGE JOIN | | 5 | |* 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | | 3 | INDEX FULL SCAN | PK_DEPT | 4 | |* 4 | SORT JOIN | | 14 | | 5 | TABLE ACCESS FULL | EMP | 14 | --------------------------------------------------------
  • 342.
    342 if joining into"d"... we must be starting with "e"
  • 343.
    343 SQL> select /*+leading(e) use_hash(d) */ * 2 from emp e, 3 dept d 4 where e.deptno = d.deptno 5 and d.dname = 'SALES'; --------------------------------------------------- | Id | Operation | Name | Rows | Bytes | --------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 285 | |* 1 | HASH JOIN | | 5 | 285 | | 2 | TABLE ACCESS FULL| EMP | 14 | 518 | |* 3 | TABLE ACCESS FULL| DEPT | 1 | 20 | ---------------------------------------------------
  • 344.
  • 345.
    345 "hints are likeviolence… if they do not work, use more"
  • 346.
    346 SQL> select /*+leading(e d b) use_hash(d) use_hash(b) */ * 2 from emp e, 3 dept d, 4 bonus b 5 where e.deptno = d.deptno 6 and d.dname = 'SALES' 7 and e.ename = b.ename; --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | |* 2 | HASH JOIN | | 5 | | 3 | TABLE ACCESS FULL| EMP | 14 | |* 4 | TABLE ACCESS FULL| DEPT | 1 | | 5 | TABLE ACCESS FULL | BONUS | 1 | ---------------------------------------------
  • 347.
    347 SQL> select /*+leading(e d b) use_hash(d) use_hash(b) */ * 2 from emp e, 3 dept d, 4 bonus b 5 where e.deptno = d.deptno 6 and d.dname = 'SALES' 7 and e.ename = b.ename; --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | | 2 | TABLE ACCESS FULL | BONUS | 1 | |* 3 | HASH JOIN | | 5 | | 4 | TABLE ACCESS FULL| EMP | 14 | |* 5 | TABLE ACCESS FULL| DEPT | 1 | ---------------------------------------------
  • 348.
    348 --------------------------------------------- | Id |Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | |* 2 | HASH JOIN | | 5 | | 3 | TABLE ACCESS FULL| EMP | 14 | |* 4 | TABLE ACCESS FULL| DEPT | 1 | | 5 | TABLE ACCESS FULL | BONUS | 1 | --------------------------------------------- --------------------------------------------- | Id | Operation | Name | Rows | --------------------------------------------- | 0 | SELECT STATEMENT | | 1 | |* 1 | HASH JOIN | | 1 | | 2 | TABLE ACCESS FULL | BONUS | 1 | |* 3 | HASH JOIN | | 5 | | 4 | TABLE ACCESS FULL| EMP | 14 | |* 5 | TABLE ACCESS FULL| DEPT | 1 | ---------------------------------------------
  • 349.
  • 350.
    350 SQL> select /*+leading(e d b) 2 use_hash(d) 3 use_hash(b) 4 no_swap_join_inputs(b) 5 */ 6 * 7 from emp e, 8 dept d, 9 bonus b 10 where e.deptno = d.deptno 11 and d.dname = 'SALES' 12 and e.ename = b.ename;
  • 351.
  • 352.
  • 353.
  • 354.
  • 355.
    355 SQL> SELECT * 2from table(dbms_xplan.display(.... , format=>'typical +OUTLINE)) /*+ BEGIN_OUTLINE_DATA USE_HASH(@"SEL$1" "B"@"SEL$1") USE_HASH(@"SEL$1" "D"@"SEL$1") LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1" "B"@"SEL$1") FULL(@"SEL$1" "B"@"SEL$1") FULL(@"SEL$1" "D"@"SEL$1") FULL(@"SEL$1" "E"@"SEL$1") OUTLINE_LEAF(@"SEL$1") ALL_ROWS DB_VERSION('11.2.0.2') OPTIMIZER_FEATURES_ENABLE('11.2.0.2') IGNORE_OPTIM_EMBEDDED_HINTS END_OUTLINE_DATA */ Ack: M.Colgan swap still possible !
  • 356.
  • 357.
  • 358.
    just hints …better in 12c 358
  • 359.
    add / removeindexes 359
  • 360.
  • 361.
  • 362.
    "an index willfix it..." 362
  • 363.
    363 SQL> select * 2from SALES 3 where SALES_DATE > ...
  • 364.
  • 365.
    365 SQL> create indexSALES_IX 2 on SALES( SALES_DATE ); Index created.
  • 366.
    366 SQL> explain planfor 2 select * from SALES 3 where sales_date > ...; -------------------------------------------------------- | Id | Operation | Name | Rows | -------------------------------------------------------- | 0 | SELECT STATEMENT | | 950 | | 1 | TABLE ACCESS BY INDEX ROWID| SALES | 950 | |* 2 | INDEX RANGE SCAN | SALES_IX | 950 | --------------------------------------------------------
  • 367.
  • 368.
  • 369.
  • 370.
  • 371.
  • 372.
    372 SQL> create tableT 2 as select * from all_objects; Table created. SQL> create index OBJ_IX on T ( OBJECT_ID); Index created. SQL> analyze table T estimate statistics; Table analyzed.
  • 373.
    373 SQL> set autotracetraceonly explain SQL> select * from T 2 where OWNER = 'SCOTT' 3 and created > sysdate - 1 4 / --------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 546 | 281 (1)| |* 1 | TABLE ACCESS FULL| T | 6 | 546 | 281 (1)| ---------------------------------------------------------------
  • 374.
  • 375.
    375 SQL> create indexNEW_IX on T ( owner); Index created. SQL> select * from T 2 where OWNER = 'SCOTT' 3 and created > sysdate - 1; --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6 | 546 | 122 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 6 | 546 | 122 (0)| |* 2 | INDEX RANGE SCAN | NEW_IX | 4107 | | 10 (0)| ---------------------------------------------------------------------------
  • 376.
  • 377.
  • 378.
    378 SQL> set autotracetraceonly explain SQL> select * from T 2 where OWNER = 'SYS' 3 and OBJECT_ID between 10 and 8000 4 / --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 462 | 42042 | 143 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 143 (0)| |* 2 | INDEX RANGE SCAN | OBJ_IX | 7851 | | 20 (0)| ---------------------------------------------------------------------------
  • 379.
    379 SQL> set autotracetraceonly stat SQL> select * from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / 4967 rows selected. Statistics ----------------------------------------------------- 0 recursive calls 0 db block gets 784 consistent gets 15 physical reads
  • 380.
  • 381.
    381 SQL> select *from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 462 | 42042 | 122 (0)| |* 1 | TABLE ACCESS BY INDEX ROWID| T | 462 | 42042 | 122 (0)| |* 2 | INDEX RANGE SCAN | NEW_IX | 4105 | | 10 (0)| --------------------------------------------------------------------------- changed !
  • 382.
    382 SQL> set autotracetraceonly stat SQL> select * from T 2 where owner = 'SYS' 3 and object_id between 10 and 8000 4 / 4967 rows selected. Statistics ------------------------------------------------------ 0 recursive calls 0 db block gets 1522 consistent gets 62 physical reads
  • 383.
  • 384.
    384 SQL> alter indexOWN_IX invisible; Index altered.
  • 385.
    385 SQL> alter sessionset 2 optimizer_use_invisible_indexes = true; Session altered. SQL> [MY QUERY] SQL> alter session set 2 optimizer_use_invisible_indexes = false; Session altered.
  • 386.
  • 387.
    if you aretuning SQL ... 387 ... you are failing
  • 388.
    tuning the userexperience 388
  • 389.
  • 390.
  • 391.