GATHER_PLAN_STATISTICS不会生成基本计划统计信息

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中也试过了,但结果没有改变.

谁能让我知道我可能错过了什么?

非常感谢.

Mat*_*eak 6

如果您运行的只是您问题中的两个语句:

select /*+ gather_plan_statistics */ * from emp;

select * from table(dbms_xplan.display(FORMAT=>'ALLSTATS LAST'));
Run Code Online (Sandbox Code Playgroud)

那么我认为你的问题是你对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.


kro*_*lko 6

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=9jjm288hx7buzCHILD_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)


wol*_*lφi 6

到目前为止我从答案中学到了什么:

解析查询时,优化器会估计查询计划的每个步骤中生成的行数。有时有必要检查预测的准确性。如果估计偏差超过一个数量级,则可能会导致使用错误的计划。

要比较估计数字和实际数字,需要执行以下步骤:

  1. V$SQL_PLAN您需要对、V$SESSION和进行读取访问V$SQL_PLAN_STATISTICS_ALL。这些权限包含在SELECT_CATALOG角色中。(来源)

  2. 打开统计收集,可以通过

    ALTER SESSION SET STATISTICS_LEVEL = ALL;

    或者使用/*+ gather_plan_statistics */查询中的提示。

    似乎有一定的性能开销。例如,请参见 Jonathan 的博客

  3. 运行查询。您稍后需要找到它,因此最好包含任意提示:

    SELECT /*+ gather_plan_statistics HelloAgain */ * FROM scott.emp;

    EXPLAIN PLAN FOR SELECT ...是不够的,因为它只会创建估计值而不运行实际查询。

    此外,正如 @Matthew 建议的那样(谢谢!),实际获取所有行很重要。大多数 GUI 仅显示前 50 行左右。在SQL Developer中,您可以在查询结果窗口中使用快捷键ctrl+End 。

  4. 在游标缓存中找到查询并记下它SQL_ID

    SELECT sql_id, child_number, sql_text FROM V$SQL WHERE sql_text LIKE '%HelloAgain%';

    dbqbqxp9srftn 0 SELECT /*+ gather_plan...

  5. 设置结果格式:

    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)


Jan*_*Jan 0

ALLSTATS LAST 在您运行该语句两次后开始工作。