- 浏览: 70804 次
- 性别:
- 来自: 杭州
文章分类
最新评论
DBMS_XPLAN.Display_Cursor 分析[转]
- 博客分类:
- Oracle SQL Tunning
Oracle 10 added the awesome procedure dbms_xplan.display_cursor but unfortunately the documentation of the package is a bit lacking and the options and output can be confusing, so here are few clarifications.
The procedure display_cursor gives the *real* execution plan instead of an estimated execution plan which is a huge relief after “explain plan”, “set autotrace on” and “dbms_xplan.display” which all output the expected execution plan. Of the the three, “set autotrace on” is the most peculiar as we can actually run the query and yet the output is the expect plan not the actually executed plan. Pheww – what a relief with dbms_xplan.display_cursor.
But, hold on to the seat of your pants, because that’s not all folks. The coolest thing is that display_cursor will output the actual execution statistics for each row source line in the real execution plan. Now that’s cool. But to access these statistics, one has to enable the collection of the statistics.
To use, run a query in SQL*Plus and include the hint
/*+ gather_plan_statistics */
then, immediately following the query execution run:
select * from table(dbms_xplan.display_cursor(null,null,’ALLSTATS’));
Then you will see the following columns in the output (minus the color coding)
A few confusing things about the output. Some of the columns are estimated statistics from the optimizer. Some of the columns are actual statistics from executing the query. And some of the columns are not per row statistics but statistics that include the statistics of the child rows.
The columns E-Rows and A-Rows can be used for Tuning by Cardinality Feedback (TCF). TCF refers to the process of comparing “E-Row” and “A-Rows” to determine whether the optimizer is optimizing correctly. The two columns “E-Rows” and “A-Rows” which represent estimated rows and actual rows can be compared to highlight how close or how far off the optimizers predictions where. If the optimizers predictions are far of, it’s an indication, though not a proof, that the query has been inadequately optimized. To get the optimizer to create an optimal execution path, one can look for ways of bringing the optimizers estimated statistics in line with the actual statistics. See Tuning by Cardinality feedback by Wolfgang Breitling.
In V$sql_plan_statistics these “should” be equal
- cardinality ~= output_rows/starts
- starts*cardinality ~= output_rows
And in the output above
- E-Rows=cardinality
- A-Rows=output_rows
Thus in order to compare E-Rows to A-Rows, we have to multiply E-Rows by starts.
Other display_cursor 3rd argument options
There are other options besides specifying “ALLSTATS” in the display_cursor. Here are a list of the options and the fields they show:
By default statistics are total for all executions of the cursor but “LAST” can be appended to the 3rd argument to get the stats for the last execution. NOTE: the last four columns on memory and temp space always show total or last as indicated above. Here is an example of using “LAST”:
select * from table ( dbms_xplan.display_cursor (null,null,’MEMSTATS LAST‘));
Notice that for memory consumption, some of the stats are bytes and some are kilo-bytes.
The above tables are images. The following table is in text for searching and copy/paste.
Arguments giving only optimizer estimates
Rows | Bytes | TempSpc | Cost | Time | |
BASIC | |||||
null | * | * | * | * | |
TYPICAL | * | * | * | * | * |
SERIAL | * | * | * | * | * |
ALL | * | * | * | * | |
ADVANCED | * | * | * | * |
Arguments that give actual row source executions statistics (the red asterisks are estimates)
(the following two tables show the same arguments, but are broken in two to fit the width)
E-Rows | starts | A-Rows | Buffers | Reads | Writes | A-Time | |
MEMSTATS | * | * | * | * | |||
ALLSTATS | * | * | * | * | * | * | * |
RUNSTATS_LAST | * | LAST | LAST | LAST | LAST | LAST | LAST |
RUNSTATS_TOT | * | TOT | TOT | TOT | TOT | TOT | TOT |
IOSTATS | * | * | * | * | * | * | * |
0Mem | 1MEM | 0/1/M | Used-Mem | Used-Tmp | Max-Tmp | |
MEMSTATS | * | * | TOT | LAST | LAST | TOT |
ALLSTATS | * | * | TOT | LAST | LAST | TOT |
RUNSTATS_LAST | ||||||
RUNSTATS_TOT | ||||||
IOSTATS |
Arguments for special cases
TQ | IN-OUT | PQ Distrib | pstart | pstop | Instance | |
PARTITION | X | X | X | |||
PARALLEL | X | X | ||||
REMOTE | X |
List of arguments for non-statistical output
predicate info | note | Query Block Name | Column projection info | outline | bind vars | |
BASIC | ||||||
null | X | X | ||||
TYPICAL | X | X | ||||
SERIAL | X | X | ||||
ALL | X | X | X | X | ||
ADVANCED | X | X | X | X | X | X |
PREDICATES | X | |||||
NOTE | X | |||||
ALIAS | X | |||||
PROJECTION | X | |||||
OUTLINES | X | |||||
PEEK_BINDS | X |
Enabling extended rows source execution statistics gathering
There are three ways to gather row source executions stats:
- /*+ gather_plan_statistics */
- sql_trace=true;
- Statistics_level=all
The first two are cheaper (sets _rowsource_statistics_sampfreq =128 ) but less accurate than the last option which though more accurate can consume signficantly more CPU (_rowsource_statistics_sampfreq =1).
Manually querying extended row source execution statistics
The data retrieved with display_cursor can be queried directly from
- v$sql_plan_statistics
- v$sql_plan_statistics_all
desc v$sql_plan_statistics ADDRESS HASH_VALUE SQL_ID PLAN_HASH_VALUE CHILD_ADDRESS CHILD_NUMBER OPERATION_ID EXECUTIONS LAST_STARTS STARTS LAST_OUTPUT_ROWS OUTPUT_ROWS LAST_CR_BUFFER_GETS CR_BUFFER_GETS LAST_CU_BUFFER_GETS CU_BUFFER_GETS LAST_DISK_READS DISK_READS LAST_DISK_WRITES DISK_WRITES LAST_ELAPSED_TIME ELAPSED_TIME
and
desc v$sql_plan_statistics_all ADDRESS HASH_VALUE SQL_ID PLAN_HASH_VALUE CHILD_ADDRESS CHILD_NUMBER TIMESTAMP OPERATION OPTIONS OBJECT_NODE OBJECT# OBJECT_OWNER OBJECT_NAME OBJECT_ALIAS OBJECT_TYPE OPTIMIZER ID PARENT_ID DEPTH POSITION SEARCH_COLUMNS COST CARDINALITY BYTES OTHER_TAG PARTITION_START PARTITION_STOP PARTITION_ID OTHER DISTRIBUTION CPU_COST IO_COST TEMP_SPACE ACCESS_PREDICATES FILTER_PREDICATES PROJECTION TIME (seconds estimated by optimizer) QBLOCK_NAME REMARKS OTHER_XML (bind vars and other info) EXECUTIONS LAST_STARTS STARTS LAST_OUTPUT_ROWS OUTPUT_ROWS LAST_CR_BUFFER_GETS CR_BUFFER_GETS LAST_CU_BUFFER_GETS CU_BUFFER_GETS LAST_DISK_READS DISK_READS LAST_DISK_WRITES DISK_WRITES LAST_ELAPSED_TIME ELAPSED_TIME (microseconds) POLICY ESTIMATED_OPTIMAL_SIZE (bytes) ESTIMATED_ONEPASS_SIZE (bytes) LAST_MEMORY_USED (bytes) LAST_EXECUTION (LAST whether work area was optimal, one pass or multi) LAST_DEGREE TOTAL_EXECUTIONS (number of times work area was active) OPTIMAL_EXECUTIONS ONEPASS_EXECUTIONS MULTIPASSES_EXECUTIONS ACTIVE_TIME (centi-seconds, time work area is active) MAX_TEMPSEG_SIZE (kb - mis-documented as bytes, though correctly bytes in v$sql_workarea ) LAST_TEMPSEG_SIZE (kb - "" , see http://www.antognini.ch/2009/05/wrong-information-about-temporary-space-usage/ ) )
so you can write a query to get the data directly such as
col operation for a45 SELECT LPAD(' ',depth)||P.OPERATION||'_'||P.OPTIONS||' '||P.OBJECT_NAME operation , last_starts * cardinality e_rows_x_starts , last_output_rows a_rows , LAST_CR_BUFFER_GETS bgets , LAST_DISK_READS pread , LAST_DISK_WRITES pwrites , LAST_ELAPSED_TIME elapsed , LAST_MEMORY_USED , LAST_TEMPSEG_SIZE , LAST_EXECUTION FROM V$SQL_PLAN_statistics_all P WHERE sql_id='&sql_id' order by child_number,id /
which makes the comparison between estimate and actual easier because I can include starts*cardinality to get the e-rows_x_starts which I can compare directly to a-rows, ie output_rows.
Putting it all together
We can take the TCF ideas farther by putting them together in a query such that the output is easier to read:
col cn format 99 col ratio format 99 col ratio1 format A6 --set pagesize 1000 set linesize 140 break on sql_id on cn col lio_rw format 999 col "operation" format a60 col a_rows for 999,999,999 col e_rows for 999,999,999 col elapsed for 999,999,999 Def v_sql_id=&SQL_ID select -- sql_id, --hv, childn cn, --ptime, stime, case when stime - nvl(ptime ,0) > 0 then stime - nvl(ptime ,0) else 0 end as elapsed, nvl(trunc((lio-nvl(plio,0))/nullif(a_rows,0)),0) lio_ratio, --id, --parent_id, --starts, --nvl(ratio,0) TCF_ratio, ' '||case when ratio > 0 then rpad('-',ratio,'-') else rpad('+',ratio*-1 ,'+') end as TCF_GRAPH, starts*cardinality e_rows, a_rows, --nvl(lio,0) lio, nvl(plio,0) parent_lio, "operation" from ( SELECT stats.LAST_ELAPSED_TIME stime, p.elapsed ptime, stats.sql_id sql_id , stats.HASH_VALUE hv , stats.CHILD_NUMBER childn , to_char(stats.id,'990') ||decode(stats.access_predicates,null,null,'A') ||decode(stats.filter_predicates,null,null,'F') id , stats.parent_id , stats.CARDINALITY cardinality , LPAD(' ',depth)||stats.OPERATION||' '|| stats.OPTIONS||' '|| stats.OBJECT_NAME|| DECODE(stats.PARTITION_START,NULL,' ',':')|| TRANSLATE(stats.PARTITION_START,'(NRUMBE','(NR')|| DECODE(stats.PARTITION_STOP,NULL,' ','-')|| TRANSLATE(stats.PARTITION_STOP,'(NRUMBE','(NR') "operation", stats.last_starts starts, stats.last_output_rows a_rows, (stats.last_cu_buffer_gets+stats.last_cr_buffer_gets) lio, p.lio plio, trunc(log(10,nullif (stats.last_starts*stats.cardinality/ nullif(stats.last_output_rows,0),0))) ratio FROM v$sql_plan_statistics_all stats , (select sum(last_cu_buffer_gets + last_cr_buffer_gets) lio, sum(LAST_ELAPSED_TIME) elapsed, child_number, parent_id, sql_id from v$sql_plan_statistics_all group by child_number,sql_id, parent_id) p WHERE stats.sql_id='&v_sql_id' and p.sql_id(+) = stats.sql_id and p.child_number(+) = stats.child_number and p.parent_id(+)=stats.id ) order by sql_id, childn , id /
which gives output like
Enter value for sql_id: g2w9n4gksyys6 old 59: stats.sql_id='&v_sql_id' and new 59: stats.sql_id='g2w9n4gksyys6' and CN ELAPSED LIO_RATIO TCF_GRAPH E_ROWS A_ROWS operation --- ------------ --------- ------ ------------ ------------ ------------------------------------------------------------ 0 0 0 1 SELECT STATEMENT 5,720,456 0 1 1 HASH GROUP BY 29,711 0 1,909 NESTED LOOPS 0 0 +++ 1 1,909 NESTED LOOPS 1,969,304 0 +++ 1 1,909 NESTED LOOPS 0 0 +++ 1 2,027 NESTED LOOPS 7,939,649 0 +++ 1 1,656 NESTED LOOPS 716,054 0 +++ 1 1,657 NESTED LOOPS 270,201 0 ++ 39 23,171 HASH JOIN 23 0 5 1 JOIN FILTER CREATE :BF0000 31 1 5 1 TABLE ACCESS BY INDEX ROWID PS_PAY_CALENDAR 14 2 5 1 INDEX RANGE SCAN PS0PAY_CALENDAR 141,467 0 18,503 23,171 VIEW VW_SQ_1 3,032,120 0 18,503 23,171 HASH GROUP BY 152,564 0 163,420 33,020 JOIN FILTER USE :BF0000 407,746 0 163,420 33,020 MERGE JOIN 55 0 5 1 SORT JOIN 12 2 5 1 INDEX RANGE SCAN PS0PAY_CALENDAR 79,435 0 40,000 33,020 SORT JOIN 119,852 0 40,000 40,000 INDEX FAST FULL SCAN WB_JOB 2,959,031 13 - 23,171 1,657 TABLE ACCESS BY INDEX ROWID WB_JOB 944,887 1 23,171 23,174 INDEX RANGE SCAN WB_JOB 102,650 0 1,657 1,656 VIEW PUSHED PREDICATE VW_SQ_2 73,769 0 1,657 1,657 SORT AGGREGATE 25,617 0 1,657 1,657 FIRST ROW 225,497 1 1,657 1,657 INDEX RANGE SCAN (MIN/MAX) WB_JOB 357,872 0 3,312 2,027 TABLE ACCESS BY INDEX ROWID WB_RETROPAY_EARNS 3,655,774 1 3,312 2,027 INDEX RANGE SCAN WB_RETROPAY_EARNS_IDX1 199,884 0 2,027 1,909 TABLE ACCESS BY INDEX ROWID PS_RETROPAY_RQST 317,793 1 2,027 1,909 INDEX RANGE SCAN PS_RETROPAY_RQST 71,534 0 1,909 1,909 INDEX RANGE SCAN PS#RETROPAYPGM_TBL 18,396 0 1,909 1,909 TABLE ACCESS BY INDEX ROWID PS_RETROPAYPGM_TBL
The 3 important parts of this query are
- Elapsed is per row source, not cumulative of it’s children
- LIO_RATIO
- TCP_GRAPH
Elapsed time format has a huge drawback in the display_cursor output as each lines elapsed time includes the elapsed time of all the children which makes an execution plan difficult to scan and see where the time is being spent. In the above output the elapsed time represents the elapsed time of each row source line.
LIO_RATIO shows the number of buffers accessed per row returned. Ideally 1 buffer or less is accessed per row returned. When the number of buffers per row becomes large, it’s a good indication that there is a more optimal method to get the rows. The I/O stats include the stats of the child row source, so the query has to get the I/O from the childern and subtract from the parent, making the query a bit more complex.
TCP_GRAPH graphically shows the ratio of estimated rows to actual rows. The estimated rows used is cardinality* starts, not just cardinality. This value can be compared directly to actual_rows and the difference in order of magnitude is shown. Each ‘+’ represents and order of magnitude larger and each “-” represents an order of magnitude smaller. The more orders of magnitude, either way, the more the optimizers calculations are off and thus like more pointing to a possible plan that is suboptimal.
In the above output there are 5 lines where the optimizer only expect 1 row and the actual results were over 1000, ie 3 orders of magnitude difference. These are the three lines with “+++”
There is one line with “-” where actual was an order of magnitude smaller. On that same line we see it’s one of the slower lines almost 3 seconds and that the were 13 lio’s per row returned, which is sign of inefficiency.
http://dboptimizer.com/2011/09/20/display_cursor/
发表评论
-
Oracle Session 视图[转]
2013-03-06 10:17 977v$session v$session_wait v$ ... -
10G中查看历史执行计划信息[转]
2013-03-01 11:02 3764现在总结下10G的,使用的是AWR报告中的信息,主要是查询 ... -
[转]解决ora-01652无法通过128(在temp表空间中)扩展temp段的过程
2012-11-28 11:11 852Tag: http://www.oraclefans. ... -
Estimate TEMP usage without running SQL [转]
2012-11-28 11:09 786Estimate TEMP usage without run ... -
[转]Optimizing SPLIT PARTITION and SPLIT SUBPARTITION Operations
2012-11-27 15:11 913Optimizing SPLIT PARTITION and ... -
Oracle splitting partitions简单小结[转]
2012-11-27 15:12 998http://www.oracleonlinux.cn/201 ... -
When the explanation doesn't sound quite right
2012-10-30 13:05 0When the explanatio ... -
Bind variables - The key to application performance[转]
2012-11-27 15:16 777Overview If you've been ... -
not in/not exists 的 null 陷阱
2012-09-27 11:07 0[转]not in/not exists 的 nul ... -
Oracle中组合索引的使用详解[转]
2012-11-27 15:15 796Oracle中组合索引的使用详解 在Oracle中可以创 ... -
跳跃式索引(Skip Scan Index)的浅析[转]
2012-12-27 10:51 1206跳跃式索引(Skip Scan Index)的浅析 [Eng ...
相关推荐
3. `xplan.display_cursor.sql` - 这个文件可能用于显示共享游标(也称为SQL语句的软解析结果)的执行计划,有助于了解当前会话中的SQL性能。 4. `xplan.display.sql` - 这可能是通用的DBMS_XPLAN显示函数的调用...
DBMS_XPLAN是Oracle提供的一个用于查看SQL计划,包括执行计划和解释计划的包;在以前查看SQL执行计划的时候,我都是使用set autotrace命令,不过现在看来,DBMS_XPLAN包给出了更加简化的获取和显示计划的方式。 这5...
本文档详细介绍了几种不同的方法来获取SQL语句的执行计划,包括使用autotrace、EXPLAIN PLAN以及DBMS_XPLAN.DISPLAY_CURSOR等。 #### 方法1:使用autotrace查看执行计划 **配置使用autotrace** 为了能够使用...
- 使用`DBMS_XPLAN.DISPLAY_CURSOR`显示执行计划,查找`dynamic sampling`关键字。 - 使用`DBMS_STATS.SET_DYNAMIC_SAMPLING`设置动态采样的级别。 - **2.1.12 Oracle AIO(异步IO)** - 异步IO是一种高级技术,...
这条SQL命令使用`dbms_xplan.display_cursor`过程来显示指定SQL_ID(`dw8z3gz4hj1d1`)的执行计划。参数`ADVANCED`表示以高级模式显示执行计划,包括更多细节。 2. **获取历史执行计划** ```sql select distinct ...
- 使用`EXPLAIN PLAN FOR`、`DBMS_XPLAN.DISPLAY`和`DBMS_XPLAN.DISPLAY_CURSOR`等工具来查看和理解SQL的执行计划,这有助于识别可能的性能瓶颈,如全表扫描、排序操作、连接方法等。 3. **SQL Trace与TKPROF**: ...
Oralce 19c执行计划调优学习笔记 1_执行计划.pdf 2_explain plan for.pdf 3_dbms_xplan.display_cursor.pdf 4_执行计划顺序.pdf 5_直方图.pdf
这个存储过程可以帮助我们省去手动输入`EXPLAIN PLAN FOR`和`DBMS_XPLAN.DISPLAY()`等命令的步骤,使得分析执行计划的过程更加便捷。以下是创建这样一个存储过程的详细步骤和相关知识点: 首先,创建存储过程的代码...
通过查询动态性能视图,如`V$SESSION`和`V$SQL`,可以找到SQL语句的游标信息,然后使用`DBMS_XPLAN.DISPLAY_CURSOR`函数来显示对应的执行计划。这种方法可以获取到最新的执行计划信息。 3. 查询历史执行计划(DBMS_...
使用`DBMS_XPLAN.DISPLAY`或`DBMS_XPLAN.DISPLAY_CURSOR`函数,可以获取带有格式化的执行计划和额外的统计信息。 3. **执行计划的分析** - **操作符**:执行计划由一系列操作符组成,如TABLE ACCESS(表访问)、...
- 使用 `EXPLAIN PLAN FOR`: 配合 `DBMS_XPLAN.DISPLAY_CURSOR` 来获取执行计划。 - 使用 `DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION`: 同样会将 SQL 的执行情况记录到追踪文件中。 **3. 如何使用 CBO, CBO 与 RULE 的...
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR); ``` 或者使用Autotrace的`TRACEONLY`和`EXPLAIN`选项: ```sql SET AUTOTRACE TRACEONLY EXPLAIN SELECT * FROM EMP; ``` 了解并熟练运用这些工具,可以帮助我们...
- 使用`DBMS_XPLAN.DISPLAY_CURSOR`查看执行计划。 2. **调整事务设计**: - 尽量减少事务的执行时间,避免长时间持有锁。 - 在可能的情况下,采用乐观锁定代替悲观锁定。 3. **利用ADDM(Automatic Database ...
4. **`DBMS_XPLAN.DISPLAY_CURSOR`**:可以查看查询计划,了解并行执行的具体细节。 #### 七、并行OLAP系统 在OLAP(联机分析处理)系统中,Oracle并行执行尤为重要。OLAP系统通常需要处理大量的数据,并且经常...
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); ``` 这可以帮助优化查询性能,了解数据库如何处理查询,包括使用的索引、连接方法等。 3. **文本操作**: Oracle提供了一系列函数来处理字符串,如`SUBSTR`用于提取...
使用 `SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));` 查看包含详细统计信息的执行计划。 - **其他技巧**: - 使用 `/*+ GATHER_PLAN_STATISTICS */` 注释可以在不设置 `...
`EXPLAIN PLAN`用于分析SQL执行计划,`DBMS_XPLAN.DISPLAY_CURSOR`查看执行计划的详细信息,`V$SESSION_WAIT`和`V$SYSTEM_EVENT`视图用于监控系统等待事件。 14. **权限管理**: `GRANT`和`REVOKE`用于赋予和撤销...
在Oracle 10g中,可以使用`dbms_xplan.display_cursor()`来获取实际执行的计划,这是比早期版本更可靠的方法,因为它直接来源于`V$sql_plan`视图。然而,在9i及更早版本中,可能需要依赖其他如SQL_TRACE和AUTOTRACE...
- `EXPLAIN PLAN`或`DBMS_XPLAN.DISPLAY`:用于分析查询计划和索引使用。 10. **视图(VIEW)** - 视图是虚拟表,基于一个或多个表的查询结果,如`CREATE VIEW view_name AS SELECT ...;`。 11. **存储过程和...