use*_*640 10 sql oracle performance
所有,
当我运行以下内容时,我正在学习调整查询:
select /*+ gather_plan_statistics */ * from emp;
select * from table(dbms_xplan.display(FORMAT=>'ALLSTATS LAST'));
Run Code Online (Sandbox Code Playgroud)
结果总是说:
- 警告:基本计划统计信息不可用.这些仅在以下情况下收集:
- 提示'gather_plan_statistics'用于语句或
- 参数'statistics_level'在会话或系统级别设置为'ALL'
我alter session set statistics_level = ALL;
在sqlplus中也试过了,但结果没有改变.
谁能让我知道我可能错过了什么?
非常感谢.
如果您运行的只是您问题中的两个语句:
Run Code Online (Sandbox Code Playgroud)select /*+ gather_plan_statistics */ * from emp; select * from table(dbms_xplan.display(FORMAT=>'ALLSTATS LAST'));
那么我认为你的问题是你对DBMS_XPLAN.DISPLAY
. 您使用它的方式是打印您解释的最后一条语句的计划,而不是您执行的最后一条语句。并且“explain”不会执行查询,因此它不会从gather_plan_statistics
提示中受益。
这在 12c 中对我有用:
select /*+ gather_plan_statistics */ count(*) from dba_objects;
SELECT *
FROM TABLE (DBMS_XPLAN.display_cursor (null, null, 'ALLSTATS LAST'));
Run Code Online (Sandbox Code Playgroud)
即,display_cursor
而不仅仅是display
.
DISPLAY 函数显示由EXPLAIN PLAN FOR命令生成(填充)的 PLAN_TABLE 的内容。因此,您可以使用 EXPLAIN PLAN FOR 命令使用它来生成和显示(理论)计划,例如以这种方式:
create table emp as select * from all_objects;
explain plan for
select /*+ gather_plan_statistics */ count(*) from emp where object_id between 100 and 150;
select * from table(dbms_xplan.display );
Plan hash value: 2083865914
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 351 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 5 | | |
|* 2 | TABLE ACCESS FULL| EMP | 12 | 60 | 351 (1)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("OBJECT_ID"<=150 AND "OBJECT_ID">=100)
Run Code Online (Sandbox Code Playgroud)
/*+ gather_plan_statistics */ 提示不会将数据保存到 PLAN_TABLE 中,而是将执行统计信息保存在 V$SQL_PLAN 性能视图中。
要显示这些数据,您可以使用此处描述的方法:http : //www.dba-oracle.com/t_gather_plan_statistics.htm,但这并不总是有效,因为您必须在 SQL 查询之后立即执行第二个命令。
更好的方法是查询V$SQL视图,获取查询的SQL_ID,然后使用DISPLAY_CURSOR函数,例如这样:
select /*+ gather_plan_statistics */ count(*) from emp where object_id between 100 and 150;
select sql_id, plan_hash_value, child_number, executions, fetches, cpu_time, elapsed_time, physical_read_requests, physical_read_bytes
from v$sql s
where sql_fulltext like 'select /*+ gather_plan_statistics */ count(*)%from emp%'
and sql_fulltext not like '%from v$sql' ;
SQL_ID PLAN_HASH_VALUE CHILD_NUMBER EXECUTIONS FETCHES CPU_TIME ELAPSED_TIME PHYSICAL_READ_REQUESTS PHYSICAL_READ_BYTES
------------- --------------- ------------ ---------- ---------- ---------- ------------ ---------------------- -------------------
9jjm288hx7buz 2083865914 0 1 1 15625 46984 26 10305536
Run Code Online (Sandbox Code Playgroud)
上面的查询返回SQL_ID=9jjm288hx7buz
和CHILD_NUMBER=0
(子编号只是一个游标编号)。使用这些值来查询收集的计划:
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('9jjm288hx7buz', 0, 'ALLSTATS'));
SQL_ID 9jjm288hx7buz, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from emp where object_id
between 100 and 150
Plan hash value: 2083865914
-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | | 2 |00:00:00.05 | 10080 |
| 1 | SORT AGGREGATE | | 2 | 1 | 2 |00:00:00.05 | 10080 |
|* 2 | TABLE ACCESS FULL| EMP | 2 | 47 | 24 |00:00:00.05 | 10080 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(("OBJECT_ID"<=150 AND "OBJECT_ID">=100))
Run Code Online (Sandbox Code Playgroud)
到目前为止我从答案中学到了什么:
解析查询时,优化器会估计查询计划的每个步骤中生成的行数。有时有必要检查预测的准确性。如果估计偏差超过一个数量级,则可能会导致使用错误的计划。
要比较估计数字和实际数字,需要执行以下步骤:
V$SQL_PLAN
您需要对、V$SESSION
和进行读取访问V$SQL_PLAN_STATISTICS_ALL
。这些权限包含在SELECT_CATALOG
角色中。(来源)
打开统计收集,可以通过
ALTER SESSION SET STATISTICS_LEVEL = ALL;
或者使用/*+ gather_plan_statistics */
查询中的提示。
似乎有一定的性能开销。例如,请参见 Jonathan 的博客。
运行查询。您稍后需要找到它,因此最好包含任意提示:
SELECT /*+ gather_plan_statistics HelloAgain */ * FROM scott.emp;
EXPLAIN PLAN FOR SELECT ...
是不够的,因为它只会创建估计值而不运行实际查询。
此外,正如 @Matthew 建议的那样(谢谢!),实际获取所有行很重要。大多数 GUI 仅显示前 50 行左右。在SQL Developer中,您可以在查询结果窗口中使用快捷键ctrl+End 。
在游标缓存中找到查询并记下它SQL_ID
:
SELECT sql_id, child_number, sql_text
FROM V$SQL
WHERE sql_text LIKE '%HelloAgain%';
dbqbqxp9srftn 0 SELECT /*+ gather_plan...
设置结果格式:
SELECT *
FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('dbqbqxp9srftn',0,'ALLSTATS LAST'));
步骤 4. 和步骤 5. 可以合并:
SELECT x.*
FROM v$sql s,
TABLE(DBMS_XPLAN.DISPLAY_CURSOR(s.sql_id, s.child_number)) x
WHERE s.sql_text LIKE '%HelloAgain%';
Run Code Online (Sandbox Code Playgroud)
结果显示估计行数 ( E-Rows
) 和实际行数 ( A-Rows
):
SQL_ID dbqbqxp9srftn, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics HelloAgain */ * FROM scott.emp
Plan hash value: 3956160932
------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 14 |00:00:00.01 | 6 |
| 1 | TABLE ACCESS FULL| EMP | 1 | 14 | 14 |00:00:00.01 | 6 |
------------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)