Oracle SQL Tuning ⼀一天之旅 申建忠(9i/10g/11g OCM)
SQL Statements • DML • SELECT • INSERT/UPDATE/DELETE/MERGE • DDL • CREATE/ALTER/DROP/TRUNCATE • DML on Data Dictionary • DCL • GRANT/REVOKE • TCL • COMMIT/REVOKE/SAVEPOINT
SQL Execution Flow Parse Execute Fetch (Select only) Server Process $ sqlplus hr/hr@orcl SQL> select last_name,salary from employees where employee_id=100; User Process Instance Database Oracle Server SQL Shared Pool Buffer Cache Log Buffer DML only Data files LAST_NAME SALARY ------------------------- ---------- King 24000 Result
Row Source Generator Syntax analysis Semantic analysis Query Transformer Estimator Plan Generator Data Dictionary Parser Optimizer optimizer statistics Hash(SQL) Soft Parse Hard Parse Parse Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Shared Pool (Library Cache) Server Process
效能問題種類 Performanc e OS DB Application Code (SQL) Design & Architecture 20% 60% 15% 5%
Tuning Cost and Benefit Time Low High Design Development Production Cost Benefit
Response Time Throughput Time Response time Wait time Service time Response time=Service time+wait time
RT Breakdown User AP Server DB Server Disk T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 Time Parse Execute Physical I/O Execute Execute Fetch Process User Request Generate SQL Process SQL Result Generate Web Page Request Response Memory Logical I/O Firewall Physical I/O Execute T13 T14 Time Network filter
Which SQL need Tune • SQL敘述句的執⾏行效率達不到之前所設 定的要求。 • Response Time • 單⼀一SQL敘述句的整體反應時間 • Throughput • 單位時間裡,同時執⾏行的SQL敘述句數 量
Why SQL need Tune • 執⾏行多餘或無謂的操作 • 不必要的SORT操作 • 不必要的Table Join操作 • 使⽤用不必要的函數 • 發⽣生⼀一些等待事件(Wait event) • 不必要的等待 • Lock wait
OLTP/DW • OLTP • 避免Hard Parse • Response Time • Throughput • Index Access • DW • 不介意Hard Parse • Response Time • Full Table Scan
OLTP/DW A Data Warehouse(DW) is a relational database that is designed for query and analysis rather than for transaction processing. It usually contains historical data derived from transaction data, but it can include data from other sources. It separates analysis workload from transaction workload and enables an organization to consolidate data from several sources. In addition to a relational database, a data warehouse environment includes an extraction, transportation, transformation, and loading (ETL) solution, an online analytical processing (OLAP) engine, client analysis tools, and other applications that manage the process of gathering data and delivering it to business users. An Online Transaction Processing (OLTP) systems are characterized by high throughput, many users, and a mix of DML operations (insert, update, and delete) and queries.
Difference between OLTP and DW OLTP DW 3rd Normal Form 表格設計 3NF/Star Schema 多 索引 少 多 Join 中 Normalized DB 資料重覆 DeNormalized DB 少 衍⽣生與彙總 資料 多 事先定義 SELECT Ad Hoc 次數多 每次資料量少 DML 次數少 每次資料量⼤大 Response Time⼩小 Throughput⼤大 系統要求 Response Time⼩小
OLTP OLTP OLTP External Source DML DML DML DML DML DML DML Extract Transform Load Data Mart Data Mart Data Mart Data Warehouse OLAP BI Ad Hoc Query Report Operational Data Source OLTP與DW的關聯
SQL Tuning on 設計階段 • 在OLTP環境下,可以考慮在WHERE⼦子句 中,使⽤用BindVariable取代Literal,以避免 過多的Hard Parse。 • 避免Table與View進⾏行 Join,以避免產⽣生 Cartesian Join。 • 使⽤用命名規則,以增加SQL的可讀性與 可維護性。 • 指令的⼤大⼩小寫、注解的使⽤用 • 使⽤用Hint前,需要審慎評估。
Hard Parse - 1 SQL> select count(*) from hr.emp where job_id='SA_REP'; COUNT(*) ---------- 30 SQL> select count(*) from hr.emp where JOB_ID='SA_REP'; COUNT(*) ---------- 30 SQL> select sql_id,hash_value,plan_hash_value,executions,sql_text 2 from v$sql 3 where sql_text like 'select count(*) from hr.emp where %'; SQL_ID HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ------------- ---------- --------------- ---------- SQL_TEXT -------------------------------------------------------------------------------------- 8rtytfkcsw4wd 2576225165 2083865914 1 select count(*) from hr.emp where job_id='SA_REP' asax0q4n558hw 676504092 2083865914 1 select count(*) from hr.emp where JOB_ID='SA_REP'
Hard Parse-2 SQL> select count(*) from hr.emp --在hr.emp之後有⼀一個不可⾒見字元n 2 where job_id='SA_REP'; COUNT(*) ---------- 30 SQL> SELECT sql_id,hash_value,executions,plan_hash_value,sql_text 2 FROM v$sql 3 WHERE sql_text like 'select count(*) from hr.emp where %'; SQL_ID HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ------------- ---------- --------------- ---------- SQL_TEXT -------------------------------------------------------------------------------- 8rtytfkcsw4wd 2576225165 2083865914 1 select count(*) from hr.emp where job_id='SA_REP' asax0q4n558hw 676504092 2083865914 1 select count(*) from hr.emp where JOB_ID='SA_REP' 0v9928mstgq0g 4053260303 2083865914 1 select count(*) from hr.emp where job_id='SA_REP'
Hard Parse - 3 SQL> select last_name from hr.employees where employee_id=100; LAST_NAME ------------------------- King SQL> select last_name from hr.employees where employee_id=200; LAST_NAME ------------------------- Whalen SQL> SELECT hash_value,plan_hash_value,executions,sql_text 2 FROM v$sql 3 WHERE sql_text like 'select last_name from hr.employees where employee_id=%'; HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ---------- --------------- ---------- SQL_TEXT ------------------------------------------------------------------------------------ 2627784799 1833546154 1 select last_name from hr.employees where employee_id=200 280342537 1833546154 1 select last_name from hr.employees where employee_id=100
Hard Parse - 4 SQL> variable empid number --此⽅方式僅適⽤用在sqlplus,sql developer等.不過java/NET也有類似語法 SQL> execute :empid := 101; SQL> select last_name from hr.employees where employee_id=:empid; LAST_NAME ------------------------- Kochhar SQL> execute :empid := 201; SQL> select last_name from hr.employees where employee_id=:empid; LAST_NAME ------------------------- Hartstein SQL> SELECT hash_value,plan_hash_value,executions sql_text 2 FROM v$sql 3 WHERE sql_text like 'select last_name from hr.employees where employee_id=%' HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ---------- --------------- ---------- SQL_TEXT ---------------------------------------------------------------------------------------------- 476476418 1833546154 2 select last_name from hr.employees where employee_id=:empid 2627784799 1833546154 1 select last_name from hr.employees where employee_id=200 280342537 1833546154 1 select last_name from hr.employees where employee_id=100
SQL Tuning on 執⾏行階段 Response time=CPU time+Wait time 必要的CPU time+ 不必要的CPU time 必要的Wait time+ 不必要的Wait time
Which SQL were High Loading ? • ADDM Report • AWR Report(Enterprise Edition) • STATSPACK(Standard Edition) • V$SQL
ADDM
AWR Report1
AWR Report2
Resource V$SQL Response Time ELAPSED_TIME Service Time CPU_TIME Sort SORTS Total I/Os BUFFER_GETS Physical I/Os DISK_READS Row Processed ROW_PROCESSED Memory RUNTIME_MEMORY Executions EXECUTIONS Critical Resources
V$SQL SQL> SELECT * 2 FROM 3 (SELECT sql_id,elapsed_time,cpu_time,buffer_gets,disk_reads,executions 4 FROM v$sql 5 ORDER BY elapsed_time DESC,cpu_time DESC, 6 buffer_gets DESC,disk_reads DESC,executions DESC) 7 WHERE ROWNUM<=10; SQL_ID ELAPSED_TIME CPU_TIME BUFFER_GETS DISK_READS EXECUTIONS ------------- ------------ ---------- ----------- ---------- ---------- 6qyqqyg14bm17 4722430672 4566883727 1171553448 1169941510 1 0a59tkkpx31vx 57267687 52511021 6414812 895 7 cj8ytxm5hhm4y 82778799 83355256 105 1 10100000 01uy9sb7w8a9g 37054402 41994 714 83 1 cvn54b7yz0s8u 25761776 942843 47660 6616 4142 3ktacv9r56b51 18381236 1381807 109780 1048 6350 39m4sx9k63ba2 15383617 449923 22739 1635 4142 ga9j9xk5cy9s0 14530703 493937 24296 752 4142 c6awqs517jpj0 9019830 340949 13858 512 4142 8swypbbr0m372 7280083 802874 100473 764 6350 10 rows selected.
V$SQL_MONITOR SQL> SELECT * 2 FROM 3 (SELECT sql_id,elapsed_time,cpu_time,queuing_time,buffer_gets,disk_reads 4 FROM v$sql_monitor 5 ORDER BY elapsed_time DESC,cpu_time DESC,queuing_time DESC 6 buffer_gets DESC,disk_reads DESC) 7 WHERE ROWNUM<=10; SQL_ID ELAPSED_TIME CPU_TIME QUEUING_TIME BUFFER_GETS DISK_READS ------------- ------------ ---------- ------------ ----------- ---------- 6qyqqyg14bm17 5396549468 5221542205 0 1337837043 17458050 ak3huf5xbg5f6 313934168 304642686 0 48 0 05s9358mm6vrr 14956086 5728129 0 195423 1744 6gvch1xu9ca3g 12560842 1741735 0 44884 1441 0a59tkkpx31vx 11246557 9412567 0 1111033 324 0a59tkkpx31vx 9080340 7986787 0 889924 494 0a59tkkpx31vx 8483972 7845806 0 886621 0 5zruc4v6y32f9 8478735 2486622 0 312062 2210 0a59tkkpx31vx 8175980 7829809 0 890517 0 f6cz4n8y72xdc 7293541 1506770 0 54905 636 10 rows selected.
找出有問題的SQL 相關table/index的 statistics是否正確 ⺫⽬目前的執⾏行計劃是 否不需要調整 調整後執⾏行計劃是 否⽐比之前更好 收集相關statistics 調整執⾏行計劃 調整執⾏行計劃之外的相關結構 完成SQL調校 平⾏行處理 使⽤用分區 改寫SQL No No No Yes Yes Yes 建⽴立索引 建⽴立實體化視觀表
Optimizer Statistics TABLE NUM_ROWS BLOCKS AVG_ROW_LEN STALE_STATS INDEX BELVEL LEAF_BLOCKS CLUSTERING_FACTOR DISTINCT_KEYS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY NUM_ROWS COLUMN NUM_DISTINCT LOW_VALUE HIGH_VALUE NUM_NULLS DENSITY NUM_BUCKETS HISTOGRAM *_TAB_STATISTICS *_IND_STATISTICS *_TAB_COL_STATISTICS
Empty/Stale Statistics SQL> SELECT num_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- SQL> SELECT num_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- 70 5 69 YES 變動量超過10% SQL> SELECT COUNT(*) FROM hr.emp; COUNT(*) ---------- 107 Staled statistics Empty statistics
Manual Gather Statistics SQL> EXECUTE DBMS_STATS.GATHER_TABLE_STATS('HR','EMP'); SQL> SELECT num_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- 107 5 69 NO SQL> EXECUTE DBMS_STATS.GATHER_SCHEMA_STATS('HR'); SQL> EXECUTE DBMS_STATS.GATHER_DATABASE_STATS; SQL> EXECUTE DBMS_STATS.GATHER_DICTIONARY_STATS; SQL> EXECUTE DBMS_STATS.GATHER_FIXED_OBJECT_STATS;
Gather Statistics Options • Estimate Percentage • Invalidate Execution Plan • Stale Percentage • Pending Publish SQL> DESC dba_tab_stat_prefs Name Null? Type ----------------------------------- -------- ---------------------------- OWNER NOT NULL VARCHAR2(30) TABLE_NAME NOT NULL VARCHAR2(30) PREFERENCE_NAME VARCHAR2(30) PREFERENCE_VALUE VARCHAR2(1000)
Finding Execution Plan • EXPLAIN PLAN(PLAN_TABLE) • AUTOTRACE(PLAN_TABLE) • Shared Pool:Library Cache(V$SQL_PLAN) • AWR(DBA_HIST_SQL_PLAN) • SQL Tuning Set • SQL Plan Baseline • Tracefile • EVENT:10046/10053
Display Execution Plan • DBMS_XPLAN.DISPLAY • DBMS_XPLAN.DISPLAY_CURSOR • DBMS_XPLAN.DISPLAY_AWR • DBMS_XPLAN.DISPLAY_SQLSET • DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE • SET AUTOTRACE ON • DBMS_SQLTUNE.REPORT_SQL_MONITOR
EXPLAIN PLAN SQL> EXPLAIN PLAN SET STATEMENT_ID='frank_demo1' FOR 2 SELECT last_name,salary FROM hr.emp WHERE employee_id=100; Explained. SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(statement_id=>'frank_demo1')); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------- Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01| |* 1 | TABLE ACCESS FULL | EMP | 1 | 16 | 3 (0)| 00:00:01| -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
AUTOTRACE SQL> SET AUTOTRACE ON SQL> SELECT last_name,salary FROM hr.emp WHERE employee_id=100; LAST_NAME SALARY ------------------------- ---------- King 24000 Execution Plan ---------------------------------------------------------- Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
V$SQL_PLAN SQL> SELECT sql_id,child_number 2 FROM v$sql 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID CHILD_NUMBER ------------- ------------ cj8ytxm5hhm4y 0 SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('cj8ytxm5hhm4y',0)); PLAN_TABLE_OUTPUT --------------------------------------------------------------------------------- SQL_ID cj8ytxm5hhm4y, child number 0 ------------------------------------- SELECT last_name,salary FROM hr.emp WHERE employee_id=100 Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
AWR SQL> SELECT sql_id 2 FROM dba_hist_sqltext 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID ------------- cj8ytxm5hhm4y SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('cj8ytxm5hhm4y')); PLAN_TABLE_OUTPUT --------------------------------------------------------------------------------- SQL_ID cj8ytxm5hhm4y, child number 0 ------------------------------------- SELECT last_name,salary FROM hr.emp WHERE employee_id=100 Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
SQL Tracefile(RAW) SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER,LEVEL 8'; SQL> SELECT last_name,salary FROM hr.emp WHERE employee_id=100; LAST_NAME SALARY ------------------------- ---------- King 24000 SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF'; orcl_ora_15492.trc ===================== PARSING IN CURSOR #140636401352696 len=57 dep=0 uid=0 oct=3 lid=0 tim=1357281071350293 hv=3406318750 ad='78fb4328' sqlid='cj8ytxm5hhm4y' SELECT last_name,salary FROM hr.emp WHERE employee_id=100 END OF STMT PARSE #140636401352696:c=20997,e=161413,p=3,cr=138,cu=0,mis=1,r=0,dep=0,og=1,plh=3956160932,tim=1357281071350286 EXEC #140636401352696:c=0,e=98,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3956160932,tim=1357281071350483 WAIT #140636401352696: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071350537 FETCH #140636401352696:c=0,e=76,p=0,cr=2,cu=0,mis=0,r=1,dep=0,og=1,plh=3956160932,tim=1357281071350647 WAIT #140636401352696: nam='SQL*Net message from client' ela= 5227 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071355930 FETCH #140636401352696:c=0,e=48,p=0,cr=2,cu=0,mis=0,r=0,dep=0,og=1,plh=3956160932,tim=1357281071356062 STAT #140636401352696 id=1 cnt=1 pid=0 pos=1 obj=77179 op='TABLE ACCESS FULL EMP (cr=4 pr=0 pw=0 time=118 us cost=3 size=16 card=1)' WAIT #140636401352696: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071356153 $ tkprof orcl_ora_15492.trc output1.txt
SQL ID: cj8ytxm5hhm4y Plan Hash: 3956160932 SELECT last_name,salary FROM hr.emp WHERE employee_id=100 call count cpu elapsed disk query current rows ----------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.04 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 4 0 1 ----------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.04 0 4 0 1 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: SYS Number of plan statistics captured: 1 Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- --------------------------------------------------- 1 1 1 TABLE ACCESS FULL EMP (cr=4 pr=0 pw=0 time=118 us cost=3 size=16 card=1) Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 2 0.00 0.00 SQL*Net message from client 2 17.86 17.87
10053 Trace SQL> SELECT sql_id 2 FROM dba_hist_sqltext 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID ------------- cj8ytxm5hhm4y SQL> EXECUTE dbms_sqldiag.dump_trace( 2> p_sql_id=>'3jb04z19uj8jf', 3> p_child_number=>0, 4> p_component=>'Compiler', 5> p_file_id=>'Hello_frank'); SQL> SELECT value FROM v$diag_info WHERE name='Default Trace File'; VALUE ------------------------------------------------------------------------- /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_3704_Hello_frank.trc
10053 Trace Content ============ Plan Table ============ -------------------------------------+-----------------------------------+ | Id | Operation | Name | Rows | Bytes | Cost | Time | -------------------------------------+-----------------------------------+ | 0 | SELECT STATEMENT | | | | 3 | | | 1 | TABLE ACCESS FULL | EMP | 1 | 40 | 3 | 00:00:01 | -------------------------------------+-----------------------------------+ Predicate Information: ---------------------- 1 - filter("EMPLOYEE_ID"=100)
V$SQL_MONITOR SQL> set pagesize 0 echo off timing off SQL> set linesize 1000 trimspool on trim on SQL> set long 2000000 longchunksize 2000000 feedback off SQL> spool sqlmonrpt_6qyqqyg14bm17.html SQL> SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(type=>’EM’,sql_id=>’6qyqqyg14bm17’) FROM dual; SQL> spool off
執⾏行計劃 --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 370M(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 | 370M (1)|999:59:59 | | 3 | TABLE ACCESS FULL| SALES | 918K| 4486K| 1233 (1)| 00:00:15 | |* 4 | TABLE ACCESS FULL| CUSTOMERS | 1 | 12 | 403 (1)| 00:00:05 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("C"."CUST_FIRST_NAME"='Dina' AND "S"."CUST_ID"="C"."CUST_ID")) 3 4 2 1 SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’
• Data Access Method • Join Order • Join Method • 每個Row Source應該盡可能減少傳給下 ⼀一個Row Source的資料量 執⾏行計劃的調整順序
Data Access Method 使⽤用者提供rowid Table Access By User Rowid 讀取所有位在High Water Mark之下的Table blocks。 Table Access Full 先透過Index找到某些rows 的ROWID,然後讀取 ROWID所指向的table blocks。 Index Range Scan Index Unique Scan Index Full Scan Index Fast Full Scan Index Skip Scan
ROWID rowid為row的相對位置資訊 rowid顯⽰示為18 characters(A-Z,a-z,0-9,+,/共64個character編碼) ABCDEFGHIJ K L M N O P Q R S T U V W X Y Z a b c d e f g.... 0123456789 1011121314151617181920212223242526272829303132.... 前6個character表⽰示為segment id(data object id) 前3個character表⽰示為relative file id(row位在哪個datafile之上) 前6個character表⽰示為block id(row位在哪個block之上) 前3個character表⽰示為row number(該block的第幾筆row) SQL> SELECT dbms_rowid.rowid_object('AAASYtAAEAAAAKnABI') data_object_id, 2 dbms_rowid.rowid_relative_fno('AAASYtAAEAAAAKnABI') relative_file_number, 3 dbms_rowid.rowid_block_number('AAASYtAAEAAAAKnABI') block_number, 4 dbms_rowid.rowid_row_number('AAASYtAAEAAAAKnABI') row_number 5 FROm dual; DATA_OBJECT_ID RELATIVE_FILE_NUMBER BLOCK_NUMBER ROW_NUMBER -------------- -------------------- ------------ ---------- 75309 4 679 72
1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18 Table Access By User Rowid
Table Access By User Rowid SQL> SELECT object_id,object_name 2> FROM hr.big1 3> WHERE rowid='AAASYtAAEAAAAKnABI'; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 12345 ALERT_QUE_N ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 42 | 1 (0)| 00:00 |* 1 | TABLE ACCESS BY USER ROWID| BIG1 | 1 | 42 | 1 (0)| 00:00 ------------------------------------------------------------------------------
Full Table Scan 1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18
Full Table Scan SQL> SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 30 | 289 (1)| 00:00:04 | |* 1 | TABLE ACCESS FULL| BIG1 | 1 | 30 | 289 (1)| 00:00:04 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("OBJECT_ID"=12345)
Index Unique Scan branch branch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid 1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18
Index Unique Scan SQL> SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| BIG1 | 1 | 42 | 2 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | BIG1_IDX1 | 1 | | 1 (0)| 00:00:01 |  ---------------------------------------------------------------------------------------- - Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=12345)
Index Range Scan Root branch branch 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 18 R R18
Index Range Scan SQL> SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| BIG1 | 1 | 42 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | BIG1_IDX1 | 1 | | 1 (0)| 00:00:01 |  ---------------------------------------------------------------------------------------- - Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=12345)
Index Full Scan branch branch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid
Index Full Scan SQL> select object_id from hr.big1 order by object_id; OBJECT_ID --------- 2 3 4 5 --其餘省略 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 72476 | 353K| 42 (0)| 00:00:01 | | 1 | INDEX FULL SCAN | BIG1_IDX1 | 72476 | 353K| 42 (0)| 00:00:01 | -----------------------------------------------------------------------------------
Index Fast Full Scan branch branch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid branch 22 rowid 23 rowid 24 rowid 16 rowid 17 rowid 18 rowid 13 rowid 14 rowid 15 rowid branch
Index Fast Full Scan SQL> select object_id from hr.big1; OBJECT_ID --------- 23456 12345 45678 34567 --其餘省略 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 72476 | 353K| 42 (0)| 00:00:01 | | 1 | INDEX FAST FULL SCAN| BIG1_IDX1 | 72476 | 353K| 42 (0)| 00:00:01 | -----------------------------------------------------------------------------------
Table Join Method • Nested Loop Join • Sort Merge Join • Hash Join • Cartesian Join
Table Join Order • ⼀一次Join操作只能結合兩個tables • 如果有4個table需要join • 則可能出現4!=24 join order • 盡量讓最⼩小的兩個table先進⾏行結合
A B 1 11 3 33 2 22 Nested Loop Join C D 33 10 44 20 55 30 11 40 11 50 22 60 A B C D 3 33 33 10 1 11 11 40 1 11 11 50 2 22 22 60 FROM t1 JOIN t2 ON (t1.b=t2.c); t1 t2
A B 1 11 3 33 2 22 Sort Merge Join C D 33 10 44 20 55 30 11 40 11 50 22 60 t1 t2 A B 1 11 2 22 3 33 C D 11 40 11 50 22 60 33 10 44 20 55 30 A B C D 1 11 11 40 1 11 11 50 2 22 22 60 3 33 33 10 FROM t1 JOIN t2 ON (t1.b=t2.c); sort sort
A B C D 1 11 11 40 1 11 11 50 2 22 22 60 3 33 33 10 A B 1 11 3 33 2 22 Hash Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 JOIN t2 ON (t1.b=t2.c); t1 t2 33 11 22 hash_area_size Build hash table Probing hash table1 2 3
A B 1 11 3 33 2 22 Cross Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 CROSS JOIN t2; t1 t2 A B C D 1 11 33 10 1 11 44 20 1 11 55 30 1 11 11 40 1 11 11 50 1 11 22 60 3 33 33 10 3 33 44 20 3 33 55 30 3 33 11 40 3 33 11 50 3 33 22 60 2 22 33 10 2 22 44 20 2 22 55 30 2 22 11 40 2 22 11 50 2 22 22 60
A B 1 11 3 33 2 22 4 66 Inner Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60
A B 1 11 3 33 2 22 4 66 Left Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 LEFT OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 4 66
A B 1 11 3 33 2 22 4 66 Right Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 RIGHT OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 44 20 55 30
A B 1 11 3 33 2 22 4 66 Full Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 FULL OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 4 66 44 20 55 30
--------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 370M(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 | 370M (1)|999:59:59 | | 3 | TABLE ACCESS FULL| SALES | 918K| 4486K| 1233 (1)| 00:00:15 | |* 4 | TABLE ACCESS FULL| CUSTOMERS | 1 | 12 | 403 (1)| 00:00:05 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("C"."CUST_FIRST_NAME"='Dina' AND "S"."CUST_ID"="C"."CUST_ID")) 解析執⾏行計劃 Data Access Method Join Method Join Order (SALES為driving table) 3 4 2 1 SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’
--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows| Bytes |Cost (%CPU)|Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 6436K(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469 | 6436K (1)|21:27:13 | | 4 | TABLE ACCESS FULL | SALES | 918K| 4486K| 1233 (1)|00:00:15 | |* 5 | INDEX RANGE SCAN | CUST_FNAME_IDX |1 | | 1 (0)|00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12 | 2 (0)|00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("C"."CUST_FIRST_NAME"='Dina') 6 - filter("S"."CUST_ID"="C"."CUST_ID") 建⽴立index在WERE⼦子句 存取customers的⽅方法 由Full Table Scan改為 Index Scan Cost由 370M降到 6 1 2 3 4 5 Time由999:59:59 降為21:27:13
-------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows| Bytes|Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |6435K(100) | | | 1 | SORT AGGREGATE | | 1 | 17| | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469|6435K (1) | 21:27:05 | | 4 | INDEX FAST FULL SCAN | SALES_CUSTID_IDX| 918K| 4486K| 535 (2) | 00:00:07 | |* 5 | INDEX RANGE SCAN | CUST_FNAME_IDX | 1 | | 1 (0) | 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12| 2 (0) | 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("C"."CUST_FIRST_NAME"='Dina') 6 - filter("S"."CUST_ID"="C"."CUST_ID") 建⽴立index在JOIN⼦子句 Cost由6436K降 到6435K Time由21:27:43 降為21:27:05 6 1 2 3 4 5
-------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows| Bytes|Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |1838K(100) | | | 1 | SORT AGGREGATE | | 1 | 17| | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469|1838K (1) | 06:07:47 | | 4 | INDEX FAST FULL SCAN | SALES_CUSTID_IDX| 918K| 4486K| 535 (2) | 00:00:07 | |* 5 | INDEX RANGE SCAN | CUST_CUSTID_IDX | 1 | | 1 (0) | 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12| 2 (0) | 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("S"."CUST_ID"="C"."CUST_ID") 6 - filter("C"."CUST_FIRST_NAME"='Dina') 建⽴立index在JOIN⼦子句 Cost由6436K降 到1838K Time由21:27:43 降為06:07:47 6 1 2 3 4 5 不使⽤用CUST_FNAME_IDX
--------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes |Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |54544 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 |54544 (1)| 00:10:55| |* 3 | TABLE ACCESS BY INDEX ROWID|CUSTOMERS | 43 | 516 |54489 (1)| 00:10:54| | 4 | INDEX FULL SCAN |CUST_CUSTID_IDX |55500 | | 125 (1)| 00:00:02| |* 5 | INDEX RANGE SCAN |SALES_CUSTID_IDX| 130 | 650 | 2 (0)| 00:00:01| --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter("C"."CUST_FIRST_NAME"='Dina') 5 - access("S"."CUST_ID"="C"."CUST_ID") 使⽤用customers當做driving table Cost由 1838K降為54544 Time由06:07:47 降為00:10:55 5 1 2 3 4 Join Order (CUSTOMERS為driving table) 不使⽤用CUST_FNAME_IDX
同時變更Data Access Method與Join Order ---------------------------------------------------------------------------------------------- | Id | Operation |Name | Rows| Bytes| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 93 (100)| | | 1 | SORT AGGREGATE | | 1| 17 | | | | 2 | NESTED LOOPS | | 5557| 94469| 93 (0)|00:00:02 | | 3 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 43| 516 | 7 (0)|00:00:01 | |* 4 | INDEX RANGE SCAN |CUSTOMERS_FNAME_IDX| 43| | 1 (0)|00:00:01 | |* 5 | INDEX RANGE SCAN |SALES_CUSTID_IDX | 130| 650| 2 (0)|00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("C"."CUST_FIRST_NAME"='Dina') 5 - access("S"."CUST_ID"="C"."CUST_ID") SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’ 3 5 2 1 4 Cost由1838K 減為93 Time由06:07:47 減為00:00:02 Join Order (CUSTOMERS為driving table)
---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 547 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | |* 2 | HASH JOIN | | 5557 | 94469 | 547 (1)| 00:00:07 | | 3 | TABLE ACCESS BY INDEX ROWID|CUSTOMERS | 43 | 516 | 7 (1)| 00:00:01 | |* 4 | INDEX FULL SCAN |CUST_FNAME_IDX | 43 | | 1 (1)| 00:00:01 | | 5 | INDEX FULL SCAN |SALES_CUSTID_IDX| 918K| 4486K| 1958 (1)| 00:00:07 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("S"."CUST_ID"="C"."CUST_ID") 4 - access("C"."CUST_FIRST_NAME"='Dina') 變更Join Method-hash join 由Nested Loop 改為Hash Join Cost由93增 加到547 Time由00:00:02 增加到00:00:07 5 1 2 3 4
變更Join Method-sort merge ---------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes| Cost (%CPU)|Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1966 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | MERGE JOIN | | 5557 | 94469| 1966 (1)|00:00:24 | | 3 | INDEX FULL SCAN |SALES_CUSTID_IDX| 918K| 4486K| 1958 (1)|00:00:24 | |* 4 | SORT JOIN | | 43 | 516 | 8 (13)|00:00:01 | | 5 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 43 | 516 | 7 (1)|00:00:01 | |* 6 | INDEX FULL SCAN | CUST_FNAME_IDX |55500 | | 1 (1)|00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("S"."CUST_ID"="C"."CUST_ID") filter("S"."CUST_ID"="C"."CUST_ID") 6 - access("C"."CUST_FIRST_NAME"='Dina') 改為Sort Merge Join Cost由93增加 到1966 Time由00:00:02 增加到00:00:24 4 1 2 3 5 6
使⽤用Index的建議 • 是否需要建⽴立 • 建⽴立在哪些欄位 • 單⼀一欄位或複合欄位 • 建⽴立何種形態 • B-Tree • Bitmap • Unique • Non-Unique
What is INDEX • An index is an optional structure, associated with a table or table cluster, that can sometimes speed data access. By creating an index on one or more columns of a table, you gain the ability in some cases to retrieve a small set of randomly distributed rows from the table. Indexes are one of many means of reducing disk I/O. Oracle® Database Concepts 11g Release 2 (11.2) -3 Indexes and Index-Organized Tables
• Index or Not Index • Index Cost • Low Selectivity(BTree Index) • Which columns • FROM/WHERE clause • Single/Multiple Column • What Type • BTree • BitMap • Uniqueness • Non-Unique • Unique
其他Data Access Method • Partitioned Table • Cluster Table • Index Cluster • Hash Cluster • Single Hash Cluster • Index Organized Table • Materialized view • Materialized view log
Q&A

Oracle Database SQL Tuning Concept

  • 1.
  • 2.
    SQL Statements • DML •SELECT • INSERT/UPDATE/DELETE/MERGE • DDL • CREATE/ALTER/DROP/TRUNCATE • DML on Data Dictionary • DCL • GRANT/REVOKE • TCL • COMMIT/REVOKE/SAVEPOINT
  • 3.
    SQL Execution Flow Parse Execute Fetch (Selectonly) Server Process $ sqlplus hr/hr@orcl SQL> select last_name,salary from employees where employee_id=100; User Process Instance Database Oracle Server SQL Shared Pool Buffer Cache Log Buffer DML only Data files LAST_NAME SALARY ------------------------- ---------- King 24000 Result
  • 4.
    Row Source Generator Syntaxanalysis Semantic analysis Query Transformer Estimator Plan Generator Data Dictionary Parser Optimizer optimizer statistics Hash(SQL) Soft Parse Hard Parse Parse Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Execution Plan Shared Pool (Library Cache) Server Process
  • 5.
  • 6.
    Tuning Cost andBenefit Time Low High Design Development Production Cost Benefit
  • 7.
    Response Time Throughput Time Response time Waittime Service time Response time=Service time+wait time
  • 8.
    RT Breakdown User APServer DB Server Disk T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 Time Parse Execute Physical I/O Execute Execute Fetch Process User Request Generate SQL Process SQL Result Generate Web Page Request Response Memory Logical I/O Firewall Physical I/O Execute T13 T14 Time Network filter
  • 9.
    Which SQL needTune • SQL敘述句的執⾏行效率達不到之前所設 定的要求。 • Response Time • 單⼀一SQL敘述句的整體反應時間 • Throughput • 單位時間裡,同時執⾏行的SQL敘述句數 量
  • 10.
    Why SQL needTune • 執⾏行多餘或無謂的操作 • 不必要的SORT操作 • 不必要的Table Join操作 • 使⽤用不必要的函數 • 發⽣生⼀一些等待事件(Wait event) • 不必要的等待 • Lock wait
  • 11.
    OLTP/DW • OLTP • 避免HardParse • Response Time • Throughput • Index Access • DW • 不介意Hard Parse • Response Time • Full Table Scan
  • 12.
    OLTP/DW A Data Warehouse(DW)is a relational database that is designed for query and analysis rather than for transaction processing. It usually contains historical data derived from transaction data, but it can include data from other sources. It separates analysis workload from transaction workload and enables an organization to consolidate data from several sources. In addition to a relational database, a data warehouse environment includes an extraction, transportation, transformation, and loading (ETL) solution, an online analytical processing (OLAP) engine, client analysis tools, and other applications that manage the process of gathering data and delivering it to business users. An Online Transaction Processing (OLTP) systems are characterized by high throughput, many users, and a mix of DML operations (insert, update, and delete) and queries.
  • 13.
    Difference between OLTP andDW OLTP DW 3rd Normal Form 表格設計 3NF/Star Schema 多 索引 少 多 Join 中 Normalized DB 資料重覆 DeNormalized DB 少 衍⽣生與彙總 資料 多 事先定義 SELECT Ad Hoc 次數多 每次資料量少 DML 次數少 每次資料量⼤大 Response Time⼩小 Throughput⼤大 系統要求 Response Time⼩小
  • 14.
  • 15.
    SQL Tuning on設計階段 • 在OLTP環境下,可以考慮在WHERE⼦子句 中,使⽤用BindVariable取代Literal,以避免 過多的Hard Parse。 • 避免Table與View進⾏行 Join,以避免產⽣生 Cartesian Join。 • 使⽤用命名規則,以增加SQL的可讀性與 可維護性。 • 指令的⼤大⼩小寫、注解的使⽤用 • 使⽤用Hint前,需要審慎評估。
  • 16.
    Hard Parse -1 SQL> select count(*) from hr.emp where job_id='SA_REP'; COUNT(*) ---------- 30 SQL> select count(*) from hr.emp where JOB_ID='SA_REP'; COUNT(*) ---------- 30 SQL> select sql_id,hash_value,plan_hash_value,executions,sql_text 2 from v$sql 3 where sql_text like 'select count(*) from hr.emp where %'; SQL_ID HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ------------- ---------- --------------- ---------- SQL_TEXT -------------------------------------------------------------------------------------- 8rtytfkcsw4wd 2576225165 2083865914 1 select count(*) from hr.emp where job_id='SA_REP' asax0q4n558hw 676504092 2083865914 1 select count(*) from hr.emp where JOB_ID='SA_REP'
  • 17.
    Hard Parse-2 SQL> selectcount(*) from hr.emp --在hr.emp之後有⼀一個不可⾒見字元n 2 where job_id='SA_REP'; COUNT(*) ---------- 30 SQL> SELECT sql_id,hash_value,executions,plan_hash_value,sql_text 2 FROM v$sql 3 WHERE sql_text like 'select count(*) from hr.emp where %'; SQL_ID HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ------------- ---------- --------------- ---------- SQL_TEXT -------------------------------------------------------------------------------- 8rtytfkcsw4wd 2576225165 2083865914 1 select count(*) from hr.emp where job_id='SA_REP' asax0q4n558hw 676504092 2083865914 1 select count(*) from hr.emp where JOB_ID='SA_REP' 0v9928mstgq0g 4053260303 2083865914 1 select count(*) from hr.emp where job_id='SA_REP'
  • 18.
    Hard Parse -3 SQL> select last_name from hr.employees where employee_id=100; LAST_NAME ------------------------- King SQL> select last_name from hr.employees where employee_id=200; LAST_NAME ------------------------- Whalen SQL> SELECT hash_value,plan_hash_value,executions,sql_text 2 FROM v$sql 3 WHERE sql_text like 'select last_name from hr.employees where employee_id=%'; HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ---------- --------------- ---------- SQL_TEXT ------------------------------------------------------------------------------------ 2627784799 1833546154 1 select last_name from hr.employees where employee_id=200 280342537 1833546154 1 select last_name from hr.employees where employee_id=100
  • 19.
    Hard Parse -4 SQL> variable empid number --此⽅方式僅適⽤用在sqlplus,sql developer等.不過java/NET也有類似語法 SQL> execute :empid := 101; SQL> select last_name from hr.employees where employee_id=:empid; LAST_NAME ------------------------- Kochhar SQL> execute :empid := 201; SQL> select last_name from hr.employees where employee_id=:empid; LAST_NAME ------------------------- Hartstein SQL> SELECT hash_value,plan_hash_value,executions sql_text 2 FROM v$sql 3 WHERE sql_text like 'select last_name from hr.employees where employee_id=%' HASH_VALUE PLAN_HASH_VALUE EXECUTIONS ---------- --------------- ---------- SQL_TEXT ---------------------------------------------------------------------------------------------- 476476418 1833546154 2 select last_name from hr.employees where employee_id=:empid 2627784799 1833546154 1 select last_name from hr.employees where employee_id=200 280342537 1833546154 1 select last_name from hr.employees where employee_id=100
  • 20.
    SQL Tuning on執⾏行階段 Response time=CPU time+Wait time 必要的CPU time+ 不必要的CPU time 必要的Wait time+ 不必要的Wait time
  • 21.
    Which SQL wereHigh Loading ? • ADDM Report • AWR Report(Enterprise Edition) • STATSPACK(Standard Edition) • V$SQL
  • 22.
  • 23.
  • 24.
  • 25.
    Resource V$SQL Response TimeELAPSED_TIME Service Time CPU_TIME Sort SORTS Total I/Os BUFFER_GETS Physical I/Os DISK_READS Row Processed ROW_PROCESSED Memory RUNTIME_MEMORY Executions EXECUTIONS Critical Resources
  • 26.
    V$SQL SQL> SELECT * 2FROM 3 (SELECT sql_id,elapsed_time,cpu_time,buffer_gets,disk_reads,executions 4 FROM v$sql 5 ORDER BY elapsed_time DESC,cpu_time DESC, 6 buffer_gets DESC,disk_reads DESC,executions DESC) 7 WHERE ROWNUM<=10; SQL_ID ELAPSED_TIME CPU_TIME BUFFER_GETS DISK_READS EXECUTIONS ------------- ------------ ---------- ----------- ---------- ---------- 6qyqqyg14bm17 4722430672 4566883727 1171553448 1169941510 1 0a59tkkpx31vx 57267687 52511021 6414812 895 7 cj8ytxm5hhm4y 82778799 83355256 105 1 10100000 01uy9sb7w8a9g 37054402 41994 714 83 1 cvn54b7yz0s8u 25761776 942843 47660 6616 4142 3ktacv9r56b51 18381236 1381807 109780 1048 6350 39m4sx9k63ba2 15383617 449923 22739 1635 4142 ga9j9xk5cy9s0 14530703 493937 24296 752 4142 c6awqs517jpj0 9019830 340949 13858 512 4142 8swypbbr0m372 7280083 802874 100473 764 6350 10 rows selected.
  • 27.
    V$SQL_MONITOR SQL> SELECT * 2FROM 3 (SELECT sql_id,elapsed_time,cpu_time,queuing_time,buffer_gets,disk_reads 4 FROM v$sql_monitor 5 ORDER BY elapsed_time DESC,cpu_time DESC,queuing_time DESC 6 buffer_gets DESC,disk_reads DESC) 7 WHERE ROWNUM<=10; SQL_ID ELAPSED_TIME CPU_TIME QUEUING_TIME BUFFER_GETS DISK_READS ------------- ------------ ---------- ------------ ----------- ---------- 6qyqqyg14bm17 5396549468 5221542205 0 1337837043 17458050 ak3huf5xbg5f6 313934168 304642686 0 48 0 05s9358mm6vrr 14956086 5728129 0 195423 1744 6gvch1xu9ca3g 12560842 1741735 0 44884 1441 0a59tkkpx31vx 11246557 9412567 0 1111033 324 0a59tkkpx31vx 9080340 7986787 0 889924 494 0a59tkkpx31vx 8483972 7845806 0 886621 0 5zruc4v6y32f9 8478735 2486622 0 312062 2210 0a59tkkpx31vx 8175980 7829809 0 890517 0 f6cz4n8y72xdc 7293541 1506770 0 54905 636 10 rows selected.
  • 28.
  • 29.
  • 30.
    Empty/Stale Statistics SQL> SELECTnum_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- SQL> SELECT num_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- 70 5 69 YES 變動量超過10% SQL> SELECT COUNT(*) FROM hr.emp; COUNT(*) ---------- 107 Staled statistics Empty statistics
  • 31.
    Manual Gather Statistics SQL>EXECUTE DBMS_STATS.GATHER_TABLE_STATS('HR','EMP'); SQL> SELECT num_rows,blocks,avg_row_len,stale_stats 2 FROM dba_tab_statistics 3 WHERE owner='HR' and table_name='EMP'; NUM_ROWS BLOCKS AVG_ROW_LEN STA ---------- ---------- ----------- --- 107 5 69 NO SQL> EXECUTE DBMS_STATS.GATHER_SCHEMA_STATS('HR'); SQL> EXECUTE DBMS_STATS.GATHER_DATABASE_STATS; SQL> EXECUTE DBMS_STATS.GATHER_DICTIONARY_STATS; SQL> EXECUTE DBMS_STATS.GATHER_FIXED_OBJECT_STATS;
  • 32.
    Gather Statistics Options •Estimate Percentage • Invalidate Execution Plan • Stale Percentage • Pending Publish SQL> DESC dba_tab_stat_prefs Name Null? Type ----------------------------------- -------- ---------------------------- OWNER NOT NULL VARCHAR2(30) TABLE_NAME NOT NULL VARCHAR2(30) PREFERENCE_NAME VARCHAR2(30) PREFERENCE_VALUE VARCHAR2(1000)
  • 34.
    Finding Execution Plan •EXPLAIN PLAN(PLAN_TABLE) • AUTOTRACE(PLAN_TABLE) • Shared Pool:Library Cache(V$SQL_PLAN) • AWR(DBA_HIST_SQL_PLAN) • SQL Tuning Set • SQL Plan Baseline • Tracefile • EVENT:10046/10053
  • 35.
    Display Execution Plan •DBMS_XPLAN.DISPLAY • DBMS_XPLAN.DISPLAY_CURSOR • DBMS_XPLAN.DISPLAY_AWR • DBMS_XPLAN.DISPLAY_SQLSET • DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE • SET AUTOTRACE ON • DBMS_SQLTUNE.REPORT_SQL_MONITOR
  • 36.
    EXPLAIN PLAN SQL> EXPLAINPLAN SET STATEMENT_ID='frank_demo1' FOR 2 SELECT last_name,salary FROM hr.emp WHERE employee_id=100; Explained. SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(statement_id=>'frank_demo1')); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------- Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01| |* 1 | TABLE ACCESS FULL | EMP | 1 | 16 | 3 (0)| 00:00:01| -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
  • 37.
    AUTOTRACE SQL> SET AUTOTRACEON SQL> SELECT last_name,salary FROM hr.emp WHERE employee_id=100; LAST_NAME SALARY ------------------------- ---------- King 24000 Execution Plan ---------------------------------------------------------- Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 16 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
  • 38.
    V$SQL_PLAN SQL> SELECT sql_id,child_number 2FROM v$sql 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID CHILD_NUMBER ------------- ------------ cj8ytxm5hhm4y 0 SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('cj8ytxm5hhm4y',0)); PLAN_TABLE_OUTPUT --------------------------------------------------------------------------------- SQL_ID cj8ytxm5hhm4y, child number 0 ------------------------------------- SELECT last_name,salary FROM hr.emp WHERE employee_id=100 Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
  • 39.
    AWR SQL> SELECT sql_id 2FROM dba_hist_sqltext 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID ------------- cj8ytxm5hhm4y SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('cj8ytxm5hhm4y')); PLAN_TABLE_OUTPUT --------------------------------------------------------------------------------- SQL_ID cj8ytxm5hhm4y, child number 0 ------------------------------------- SELECT last_name,salary FROM hr.emp WHERE employee_id=100 Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | |* 1 | TABLE ACCESS FULL| EMP | 1 | 16 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=100)
  • 40.
    SQL Tracefile(RAW) SQL> ALTERSESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER,LEVEL 8'; SQL> SELECT last_name,salary FROM hr.emp WHERE employee_id=100; LAST_NAME SALARY ------------------------- ---------- King 24000 SQL> ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF'; orcl_ora_15492.trc ===================== PARSING IN CURSOR #140636401352696 len=57 dep=0 uid=0 oct=3 lid=0 tim=1357281071350293 hv=3406318750 ad='78fb4328' sqlid='cj8ytxm5hhm4y' SELECT last_name,salary FROM hr.emp WHERE employee_id=100 END OF STMT PARSE #140636401352696:c=20997,e=161413,p=3,cr=138,cu=0,mis=1,r=0,dep=0,og=1,plh=3956160932,tim=1357281071350286 EXEC #140636401352696:c=0,e=98,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=3956160932,tim=1357281071350483 WAIT #140636401352696: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071350537 FETCH #140636401352696:c=0,e=76,p=0,cr=2,cu=0,mis=0,r=1,dep=0,og=1,plh=3956160932,tim=1357281071350647 WAIT #140636401352696: nam='SQL*Net message from client' ela= 5227 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071355930 FETCH #140636401352696:c=0,e=48,p=0,cr=2,cu=0,mis=0,r=0,dep=0,og=1,plh=3956160932,tim=1357281071356062 STAT #140636401352696 id=1 cnt=1 pid=0 pos=1 obj=77179 op='TABLE ACCESS FULL EMP (cr=4 pr=0 pw=0 time=118 us cost=3 size=16 card=1)' WAIT #140636401352696: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=1357281071356153 $ tkprof orcl_ora_15492.trc output1.txt
  • 41.
    SQL ID: cj8ytxm5hhm4yPlan Hash: 3956160932 SELECT last_name,salary FROM hr.emp WHERE employee_id=100 call count cpu elapsed disk query current rows ----------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.04 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.00 0 4 0 1 ----------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.00 0.04 0 4 0 1 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: SYS Number of plan statistics captured: 1 Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- --------------------------------------------------- 1 1 1 TABLE ACCESS FULL EMP (cr=4 pr=0 pw=0 time=118 us cost=3 size=16 card=1) Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net message to client 2 0.00 0.00 SQL*Net message from client 2 17.86 17.87
  • 42.
    10053 Trace SQL> SELECTsql_id 2 FROM dba_hist_sqltext 3 WHERE sql_text='SELECT last_name,salary FROM hr.emp WHERE employee_id=100'; SQL_ID ------------- cj8ytxm5hhm4y SQL> EXECUTE dbms_sqldiag.dump_trace( 2> p_sql_id=>'3jb04z19uj8jf', 3> p_child_number=>0, 4> p_component=>'Compiler', 5> p_file_id=>'Hello_frank'); SQL> SELECT value FROM v$diag_info WHERE name='Default Trace File'; VALUE ------------------------------------------------------------------------- /u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_3704_Hello_frank.trc
  • 43.
    10053 Trace Content ============ PlanTable ============ -------------------------------------+-----------------------------------+ | Id | Operation | Name | Rows | Bytes | Cost | Time | -------------------------------------+-----------------------------------+ | 0 | SELECT STATEMENT | | | | 3 | | | 1 | TABLE ACCESS FULL | EMP | 1 | 40 | 3 | 00:00:01 | -------------------------------------+-----------------------------------+ Predicate Information: ---------------------- 1 - filter("EMPLOYEE_ID"=100)
  • 44.
    V$SQL_MONITOR SQL> set pagesize0 echo off timing off SQL> set linesize 1000 trimspool on trim on SQL> set long 2000000 longchunksize 2000000 feedback off SQL> spool sqlmonrpt_6qyqqyg14bm17.html SQL> SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(type=>’EM’,sql_id=>’6qyqqyg14bm17’) FROM dual; SQL> spool off
  • 45.
    執⾏行計劃 --------------------------------------------------------------------------------- | Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 370M(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 | 370M (1)|999:59:59 | | 3 | TABLE ACCESS FULL| SALES | 918K| 4486K| 1233 (1)| 00:00:15 | |* 4 | TABLE ACCESS FULL| CUSTOMERS | 1 | 12 | 403 (1)| 00:00:05 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("C"."CUST_FIRST_NAME"='Dina' AND "S"."CUST_ID"="C"."CUST_ID")) 3 4 2 1 SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’
  • 46.
    • Data AccessMethod • Join Order • Join Method • 每個Row Source應該盡可能減少傳給下 ⼀一個Row Source的資料量 執⾏行計劃的調整順序
  • 47.
    Data Access Method 使⽤用者提供rowidTable Access By User Rowid 讀取所有位在High Water Mark之下的Table blocks。 Table Access Full 先透過Index找到某些rows 的ROWID,然後讀取 ROWID所指向的table blocks。 Index Range Scan Index Unique Scan Index Full Scan Index Fast Full Scan Index Skip Scan
  • 48.
    ROWID rowid為row的相對位置資訊 rowid顯⽰示為18 characters(A-Z,a-z,0-9,+,/共64個character編碼) ABCDEFGHIJ KL M N O P Q R S T U V W X Y Z a b c d e f g.... 0123456789 1011121314151617181920212223242526272829303132.... 前6個character表⽰示為segment id(data object id) 前3個character表⽰示為relative file id(row位在哪個datafile之上) 前6個character表⽰示為block id(row位在哪個block之上) 前3個character表⽰示為row number(該block的第幾筆row) SQL> SELECT dbms_rowid.rowid_object('AAASYtAAEAAAAKnABI') data_object_id, 2 dbms_rowid.rowid_relative_fno('AAASYtAAEAAAAKnABI') relative_file_number, 3 dbms_rowid.rowid_block_number('AAASYtAAEAAAAKnABI') block_number, 4 dbms_rowid.rowid_row_number('AAASYtAAEAAAAKnABI') row_number 5 FROm dual; DATA_OBJECT_ID RELATIVE_FILE_NUMBER BLOCK_NUMBER ROW_NUMBER -------------- -------------------- ------------ ---------- 75309 4 679 72
  • 49.
    1 A A1 10J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18 Table Access By User Rowid
  • 50.
    Table Access ByUser Rowid SQL> SELECT object_id,object_name 2> FROM hr.big1 3> WHERE rowid='AAASYtAAEAAAAKnABI'; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 12345 ALERT_QUE_N ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 42 | 1 (0)| 00:00 |* 1 | TABLE ACCESS BY USER ROWID| BIG1 | 1 | 42 | 1 (0)| 00:00 ------------------------------------------------------------------------------
  • 51.
    Full Table Scan 1A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18
  • 52.
    Full Table Scan SQL>SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 30 | 289 (1)| 00:00:04 | |* 1 | TABLE ACCESS FULL| BIG1 | 1 | 30 | 289 (1)| 00:00:04 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("OBJECT_ID"=12345)
  • 53.
    Index Unique Scan branchbranch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid 1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 18 R R18
  • 54.
    Index Unique Scan SQL>SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| BIG1 | 1 | 42 | 2 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | BIG1_IDX1 | 1 | | 1 (0)| 00:00:01 |  ---------------------------------------------------------------------------------------- - Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=12345)
  • 55.
    Index Range Scan Root branchbranch 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid 6 F F6 13 M M 22 V V 8 H H8 15 O O 24 X X 5 E E5 14 N N 23 W W23 9 I I9 16 P P 20 T T 1 A A1 10 J J10 17 Q Q 2 B B2 19 S S19 3 C C3 7 G G7 11 K K 4 D D4 12 L L 21 U U 18 R R18
  • 56.
    Index Range Scan SQL>SELECT rowid,object_id,object_name 2> FROM hr.big1 3> WHERE object_id=12345; ROWID OBJECT_ID OBJECT_NAME ------------------ ---------- ------------------------------ AAASYtAAEAAAAKnABI 12345 ALERT_QUE_N ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 42 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| BIG1 | 1 | 42 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | BIG1_IDX1 | 1 | | 1 (0)| 00:00:01 |  ---------------------------------------------------------------------------------------- - Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=12345)
  • 57.
    Index Full Scan branchbranch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid
  • 58.
    Index Full Scan SQL>select object_id from hr.big1 order by object_id; OBJECT_ID --------- 2 3 4 5 --其餘省略 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 72476 | 353K| 42 (0)| 00:00:01 | | 1 | INDEX FULL SCAN | BIG1_IDX1 | 72476 | 353K| 42 (0)| 00:00:01 | -----------------------------------------------------------------------------------
  • 59.
    Index Fast FullScan branch branch root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid 13 rowid 14 rowid 15 rowid 16 rowid 17 rowid 18 rowid 19 rowid 20 rowid 21 rowid 22 rowid 23 rowid 24 rowid root 1 rowid 2 rowid 3 rowid 4 rowid 5 rowid 6 rowid 7 rowid 8 rowid 9 rowid 10 rowid 11 rowid 12 rowid branch 22 rowid 23 rowid 24 rowid 16 rowid 17 rowid 18 rowid 13 rowid 14 rowid 15 rowid branch
  • 60.
    Index Fast FullScan SQL> select object_id from hr.big1; OBJECT_ID --------- 23456 12345 45678 34567 --其餘省略 ----------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 72476 | 353K| 42 (0)| 00:00:01 | | 1 | INDEX FAST FULL SCAN| BIG1_IDX1 | 72476 | 353K| 42 (0)| 00:00:01 | -----------------------------------------------------------------------------------
  • 61.
    Table Join Method •Nested Loop Join • Sort Merge Join • Hash Join • Cartesian Join
  • 62.
    Table Join Order •⼀一次Join操作只能結合兩個tables • 如果有4個table需要join • 則可能出現4!=24 join order • 盡量讓最⼩小的兩個table先進⾏行結合
  • 63.
    A B 1 11 333 2 22 Nested Loop Join C D 33 10 44 20 55 30 11 40 11 50 22 60 A B C D 3 33 33 10 1 11 11 40 1 11 11 50 2 22 22 60 FROM t1 JOIN t2 ON (t1.b=t2.c); t1 t2
  • 64.
    A B 1 11 333 2 22 Sort Merge Join C D 33 10 44 20 55 30 11 40 11 50 22 60 t1 t2 A B 1 11 2 22 3 33 C D 11 40 11 50 22 60 33 10 44 20 55 30 A B C D 1 11 11 40 1 11 11 50 2 22 22 60 3 33 33 10 FROM t1 JOIN t2 ON (t1.b=t2.c); sort sort
  • 65.
    A B CD 1 11 11 40 1 11 11 50 2 22 22 60 3 33 33 10 A B 1 11 3 33 2 22 Hash Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 JOIN t2 ON (t1.b=t2.c); t1 t2 33 11 22 hash_area_size Build hash table Probing hash table1 2 3
  • 66.
    A B 1 11 333 2 22 Cross Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 CROSS JOIN t2; t1 t2 A B C D 1 11 33 10 1 11 44 20 1 11 55 30 1 11 11 40 1 11 11 50 1 11 22 60 3 33 33 10 3 33 44 20 3 33 55 30 3 33 11 40 3 33 11 50 3 33 22 60 2 22 33 10 2 22 44 20 2 22 55 30 2 22 11 40 2 22 11 50 2 22 22 60
  • 67.
    A B 1 11 333 2 22 4 66 Inner Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60
  • 68.
    A B 1 11 333 2 22 4 66 Left Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 LEFT OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 4 66
  • 69.
    A B 1 11 333 2 22 4 66 Right Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 RIGHT OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 44 20 55 30
  • 70.
    A B 1 11 333 2 22 4 66 Full Outer Join C D 33 10 44 20 55 30 11 40 11 50 22 60 FROM t1 FULL OUTER JOIN t2 ON (t1.B=t2.C) t1 t2 A B C D 1 11 11 40 1 11 11 50 3 33 33 10 2 22 22 60 4 66 44 20 55 30
  • 71.
    --------------------------------------------------------------------------------- | Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 370M(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 | 370M (1)|999:59:59 | | 3 | TABLE ACCESS FULL| SALES | 918K| 4486K| 1233 (1)| 00:00:15 | |* 4 | TABLE ACCESS FULL| CUSTOMERS | 1 | 12 | 403 (1)| 00:00:05 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter(("C"."CUST_FIRST_NAME"='Dina' AND "S"."CUST_ID"="C"."CUST_ID")) 解析執⾏行計劃 Data Access Method Join Method Join Order (SALES為driving table) 3 4 2 1 SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’
  • 72.
    --------------------------------------------------------------------------------------------- | Id |Operation | Name | Rows| Bytes |Cost (%CPU)|Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 6436K(100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469 | 6436K (1)|21:27:13 | | 4 | TABLE ACCESS FULL | SALES | 918K| 4486K| 1233 (1)|00:00:15 | |* 5 | INDEX RANGE SCAN | CUST_FNAME_IDX |1 | | 1 (0)|00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12 | 2 (0)|00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("C"."CUST_FIRST_NAME"='Dina') 6 - filter("S"."CUST_ID"="C"."CUST_ID") 建⽴立index在WERE⼦子句 存取customers的⽅方法 由Full Table Scan改為 Index Scan Cost由 370M降到 6 1 2 3 4 5 Time由999:59:59 降為21:27:13
  • 73.
    -------------------------------------------------------------------------------------------- | Id |Operation | Name | Rows| Bytes|Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |6435K(100) | | | 1 | SORT AGGREGATE | | 1 | 17| | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469|6435K (1) | 21:27:05 | | 4 | INDEX FAST FULL SCAN | SALES_CUSTID_IDX| 918K| 4486K| 535 (2) | 00:00:07 | |* 5 | INDEX RANGE SCAN | CUST_FNAME_IDX | 1 | | 1 (0) | 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12| 2 (0) | 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("C"."CUST_FIRST_NAME"='Dina') 6 - filter("S"."CUST_ID"="C"."CUST_ID") 建⽴立index在JOIN⼦子句 Cost由6436K降 到6435K Time由21:27:43 降為21:27:05 6 1 2 3 4 5
  • 74.
    -------------------------------------------------------------------------------------------- | Id |Operation | Name | Rows| Bytes|Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |1838K(100) | | | 1 | SORT AGGREGATE | | 1 | 17| | | | 2 | NESTED LOOPS | | | | | | | 3 | NESTED LOOPS | |5557 | 94469|1838K (1) | 06:07:47 | | 4 | INDEX FAST FULL SCAN | SALES_CUSTID_IDX| 918K| 4486K| 535 (2) | 00:00:07 | |* 5 | INDEX RANGE SCAN | CUST_CUSTID_IDX | 1 | | 1 (0) | 00:00:01 | |* 6 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 12| 2 (0) | 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 5 - access("S"."CUST_ID"="C"."CUST_ID") 6 - filter("C"."CUST_FIRST_NAME"='Dina') 建⽴立index在JOIN⼦子句 Cost由6436K降 到1838K Time由21:27:43 降為06:07:47 6 1 2 3 4 5 不使⽤用CUST_FNAME_IDX
  • 75.
    --------------------------------------------------------------------------------------------- | Id |Operation | Name | Rows | Bytes |Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | |54544 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | NESTED LOOPS | | 5557 | 94469 |54544 (1)| 00:10:55| |* 3 | TABLE ACCESS BY INDEX ROWID|CUSTOMERS | 43 | 516 |54489 (1)| 00:10:54| | 4 | INDEX FULL SCAN |CUST_CUSTID_IDX |55500 | | 125 (1)| 00:00:02| |* 5 | INDEX RANGE SCAN |SALES_CUSTID_IDX| 130 | 650 | 2 (0)| 00:00:01| --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - filter("C"."CUST_FIRST_NAME"='Dina') 5 - access("S"."CUST_ID"="C"."CUST_ID") 使⽤用customers當做driving table Cost由 1838K降為54544 Time由06:07:47 降為00:10:55 5 1 2 3 4 Join Order (CUSTOMERS為driving table) 不使⽤用CUST_FNAME_IDX
  • 76.
    同時變更Data Access Method與Join Order ---------------------------------------------------------------------------------------------- |Id | Operation |Name | Rows| Bytes| Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 93 (100)| | | 1 | SORT AGGREGATE | | 1| 17 | | | | 2 | NESTED LOOPS | | 5557| 94469| 93 (0)|00:00:02 | | 3 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 43| 516 | 7 (0)|00:00:01 | |* 4 | INDEX RANGE SCAN |CUSTOMERS_FNAME_IDX| 43| | 1 (0)|00:00:01 | |* 5 | INDEX RANGE SCAN |SALES_CUSTID_IDX | 130| 650| 2 (0)|00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("C"."CUST_FIRST_NAME"='Dina') 5 - access("S"."CUST_ID"="C"."CUST_ID") SELECT COUNT(*) FROM frank.sales s,frank.customers c WHERE s.cust_id=c.cust_id AND c.cust_first_name=‘Dina’ 3 5 2 1 4 Cost由1838K 減為93 Time由06:07:47 減為00:00:02 Join Order (CUSTOMERS為driving table)
  • 77.
    ---------------------------------------------------------------------------------------------- | Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 547 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | |* 2 | HASH JOIN | | 5557 | 94469 | 547 (1)| 00:00:07 | | 3 | TABLE ACCESS BY INDEX ROWID|CUSTOMERS | 43 | 516 | 7 (1)| 00:00:01 | |* 4 | INDEX FULL SCAN |CUST_FNAME_IDX | 43 | | 1 (1)| 00:00:01 | | 5 | INDEX FULL SCAN |SALES_CUSTID_IDX| 918K| 4486K| 1958 (1)| 00:00:07 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("S"."CUST_ID"="C"."CUST_ID") 4 - access("C"."CUST_FIRST_NAME"='Dina') 變更Join Method-hash join 由Nested Loop 改為Hash Join Cost由93增 加到547 Time由00:00:02 增加到00:00:07 5 1 2 3 4
  • 78.
    變更Join Method-sort merge ---------------------------------------------------------------------------------------------- |Id | Operation | Name | Rows | Bytes| Cost (%CPU)|Time | ---------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1966 (100)| | | 1 | SORT AGGREGATE | | 1 | 17 | | | | 2 | MERGE JOIN | | 5557 | 94469| 1966 (1)|00:00:24 | | 3 | INDEX FULL SCAN |SALES_CUSTID_IDX| 918K| 4486K| 1958 (1)|00:00:24 | |* 4 | SORT JOIN | | 43 | 516 | 8 (13)|00:00:01 | | 5 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 43 | 516 | 7 (1)|00:00:01 | |* 6 | INDEX FULL SCAN | CUST_FNAME_IDX |55500 | | 1 (1)|00:00:01 | ---------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("S"."CUST_ID"="C"."CUST_ID") filter("S"."CUST_ID"="C"."CUST_ID") 6 - access("C"."CUST_FIRST_NAME"='Dina') 改為Sort Merge Join Cost由93增加 到1966 Time由00:00:02 增加到00:00:24 4 1 2 3 5 6
  • 79.
    使⽤用Index的建議 • 是否需要建⽴立 • 建⽴立在哪些欄位 •單⼀一欄位或複合欄位 • 建⽴立何種形態 • B-Tree • Bitmap • Unique • Non-Unique
  • 80.
    What is INDEX •An index is an optional structure, associated with a table or table cluster, that can sometimes speed data access. By creating an index on one or more columns of a table, you gain the ability in some cases to retrieve a small set of randomly distributed rows from the table. Indexes are one of many means of reducing disk I/O. Oracle® Database Concepts 11g Release 2 (11.2) -3 Indexes and Index-Organized Tables
  • 81.
    • Index orNot Index • Index Cost • Low Selectivity(BTree Index) • Which columns • FROM/WHERE clause • Single/Multiple Column • What Type • BTree • BitMap • Uniqueness • Non-Unique • Unique
  • 82.
    其他Data Access Method •Partitioned Table • Cluster Table • Index Cluster • Hash Cluster • Single Hash Cluster • Index Organized Table • Materialized view • Materialized view log
  • 83.