4.4.tuning SQL Execution-Plan
4.4.tuning SQL Execution-Plan
E
SQL TUNING
Agend
a
• Introduction
• Single table access
• Joins
• Useful tip & techniques
• Test case/Q&A
INTRODUCTION
SQL
SELECT F. * , D.*
FROM
SB_DTM. FCT_ACCOUNT
F, SB_DTM.DIM_ACCOUNT D
WHERE DAYI D =
TRUNC( SYSDATE) - 1 AND
F.ACCOUNT_ID = D.ACCOUNT
AND D.EXP_DATE IS NOT NULL
ORDER BY 1 , 2 ;
5
Execution Plan
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
6
Execution Plan
Query
Query
Transformations
Execution Plan
8
Query transformation
9
Costing and Access Paths
• Table/index/column statistics
• Number of rows, distinct values, number of nulls
• Min/Max
• Column histogram
• Index: Blevel; distinct keys, clustering factor
• …
• System statistics
• Multi-block read count
• Single-block/Multi-block read time
• CPU time
• …
• Optimizer parameters
• V$SES_OPTIMIZER_ENV
10
Statistic – Where does it come from?
11
View Execution Plan
• Oracle SQL Developer (F10)
• PL/SQL Developer
• Toad (Ctrl+E)
• Oracle supplied package DBMS_XPLAN (*)
• DISPLAY
• DISPLAY_CURSOR
• DISPLAY_AWR
• SQL Plus (SET AUTOTRACE ON|TRACEONLY) (*)
• SQL Monitoring (DBMS_SQLTUNE)
Reading Execution Plan
SELECT * FROM SCOTT.EMP
WHERE DEPTNO IN DEPTNO FROM SCOTT.DEPT WHERE DNAME='RESEARCH')
(SELECT AND ENAME LIKE
'C%';
Plan hash value: 351108634
14
SINGLE TABLE ACCESS
Heap table structure
16
Table Access Methods
18
Index scan
• Range scan
• WHERE NAME = :1
• WHERE LASTUPDATE BETWEEN :1 AND :2
• WHERE NAME <> :1 ?
• Unique scan – Only for Unique index
• WHERE ID= :1
• Skip scan
• Index on (col1, col2); WHERE COL2 = :1
• Full scan (should be avoided)
• Output row is sorted
• Fast full scan
• Output is not sorted
Table scan vs Index scan
• Table scan
• “most” table data. 80/20 90/10
• How many rows really need to query?
• Report/aggregate SQL
• DSS/Data warehouse
• Index scan
• Selective query
• OLTP
• Histogram (data skew)
Histogram – Data distribution
22
Forcing Tablescan or Index - Hint
• Hint
• Looks like comment: /* */
• Placement: directly after SELECT, INSERT, UPDATE,
DELETE
• Format: /*+ */
• Can be appeared in various places in a SQL
• Combine multiple keyword
• Example
• SELECT /*+ FULL(A) INDEX(B(COL1)) PARALLEL(8) */
COL1 FROM A, B WHERE …
• Full list: SQL Reference
• Only use Hint when Oracle failed to produce good
plan
23
Forcing Tablescan or Index - Hint
25
Partition Pruning
27
Summary
29
Workshop – Info
IP: 10.0.1.107
Port: 1521
DB: oracle
SID: orcl
User/pass: hr/ admin#123
Workshop – Histogram – Data
distribution
• Skip scan
• Index on (col1, col2); WHERE COL2 = :1
Workshop – Index Function
• SELECT ID FROM MT_LIST WHERE PROCESS=‘N’;
• MT_LIST: 100.000.000 rows, PROCESS=‘N’: 100
• CREATE INDEX MT_LIST_PROCESS_N_I ON MT_LIST(CASE WHEN
PROCESS=‘N’ THEN ‘N’ ELSE NULL END);
• SELECT ID FROM MT_LIST WHERE (CASE WHEN PROCESS=‘N’ THEN
‘N’ ELSE NULL END)=‘N’;
• Oracle does not index NULL value in B*Tree index (except composite
index)
• Index small
• Small overhead when update PROCESS=‘N’ to ‘Y’
29
JOINS
Join
1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
4 - filter("A1"."OPENING_DATE">=:B1
AND "A1"."OPENING_DATE"<=:B2)
6 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
Merge join
SELECT /*+ USE_MERGE(A1, A2) LEADING(A1) */ A1.*, A2.*
FROM SB_DTM.DIM_ACCOUNT A1, SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK
AND A1.OPENING_DATE BETWEEN :B1 AND :B2
- - - - - - - - - - - - - - - - - - - - - - - - - -
-
Predicate Information
1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - access("A1"."ACCOUNT_SK“
="A2"."ACCOUNT_SK")
3 - filter("A1"."OPENING_DATE">=:B1
AND "A1"."OPENING_DATE"<=:B2)
Choosing the Join Method
• Nested-loop
• Joins involving a relatively small subset
of table data and where the join is supported
by an index
• No memory overhead
• Hash/Merge join
• More suitable when a large proportion of the tables
are being joined or if there is no suitable index.
• Hash join consume less memory
• Merge join is suitable when result needed to be
sorted
• Merge join Cartesian *
Join order (Driving table)
SELECT A1.*, A2.* FROM
SB_DTM.DIM_ACCOUNT
A1,
SB_DTM.FCT_ACCOUNT A2
WHERE A1.ACCOUNT_SK=A2.ACCOUNT_SK AND
A1.OPENING_DATE BETWEEN :B1 AND :B2
AND A2.CO_CODE = :B3
P redicate I n f o r m a t i o n ( i d e n t i f i e d by o p e r a t i o n i d ) :
- - - - - - - - - - - - - - - --
1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - filter("A2"."CO_CODE"=:B3)
4 - filter("A1"."OPENING_DATE">=:B1 AND "A1"."OPENING_DATE"<=:B2)
6 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
39
Join order (Driving table)
- - - - - - - - - - - - - - - -- --
| I d | Oper at i on | Name | Rows |
- - - - - - - - - - - - - - - -- --
| 0 | SELECT STATEMENT | | 56698 |
| * 1 | FILTER | | |
|* 2 | HASH JOIN | | 56698 |
| 3 | PARTITION RANGE ALL| | 11M|
|* 4 | TABLE ACCESS FULL | FCT_ACCOUNT | 11M|
|* 5 | TABLE ACCESS FULL DIM_ACCOUNT | 27086 |
- - - - - - - - - - - - - - - -- --
|
P redicate I n f o r m a t i o n ( i d e n t i f i e d by o p e r a t i o n i d ) :
- - - - - - - - - - - - - - - --
1 - filter(TO_DATE(:B2)>=TO_DATE(:B1))
2 - access("A1"."ACCOUNT_SK"="A2"."ACCOUNT_SK")
4 - filter("A2"."CO_CODE"=:B3)
5 - filter("A1"."OPENING_DATE">=:B1 AND "A1"."OPENING_DATE"<=:B2)
40
Join order (Driving table)
• The table that returns the fewest number of rows
should be the driving table
• Filter as many rows as possible early
• nPr(n,n) possible combinations
• THE MORE TABLE JOIN, THE MORE CHANCE
ORACLE WILL PRODUCE SUB-OPTIMAL PLAN
• KISS
Forcing Join types, Order
• /*+ USE_NL(tbl1 tbl2) */
• /*+ USE_HASH(tbl1 tbl2) */
• /*+ USE_MERGE(tbl1 tbl2) */
• /*+ LEADING(tbl1 tbl2) */
Help Oracle determine best plan
46
Index with multiple column
47
Bind variable
48
Bind variable
49
SELECT * vs. SELECT COLUMN
50
Real life test case
• Group chat
h.ma_so_thue mst,
Practice
_char(dk.ngay_dangky,'dd/mm/yyyy hh24:mi:ss') ngay,
01-CA06',
ase when csh.so_cmnd is not null and csh.ma_so_thue is null then 1 -- ca nhan
when ( csh.so_cmnd is null and csh.ma_so_thue is not null )then 5 -- to chuc
when(csh.so_cmnd is not null and csh.ma_so_thue is not null) then 5
end) cn
om BCA_prod.diem_dang_ki ddk , BCA_prod.oto_portal@oto p, BCA_prod.oto oto,
CA_prod.oto_dang_ky dk , BCA_prod.oto_chu_so_huu csh,
CA_prod.dia_danh_hanh_chinh@oto hc
here ddk.id = dk.DIEM_DK_ID
nd ddk.dia_danh_cap_cuoi = hc.id
nd ddk.dia_danh_cap_cuoi in (select id from bca_prod.dia_danh_hanh_chinh )
nd dk.chu_so_huu_id = csh.id
nd oto.so_khung not in (select p.so_khung from BCA_prod.oto_portal@oto
here p.ngay_tao between to_date('10/11/2022', 'dd/MM/yyyy') and to_date('10/12/2022',
d/MM/yyyy'))
nd oto.id = dk.oto_id
nd dk.trangthai_dangky in('01','03','04','06','07','10','12')
nd dk.ngay_dangky between to_date('10/11/2022', 'dd/MM/yyyy') and to_date('10/12/2022',
d/MM/yyyy')
nd (ddk.ten not like '%Test%' or ddk.ten not like '%test%' ) ORDER BY madd, caphc, loaidk
Q&A
Thank you!