dbms_xplan.display查不到刚执行sql是因为它默认读plan_table且需手动填充,而display_cursor才从v$sql_plan查真实执行计划;需注意权限、统计开关及共享池生命周期。
dbms_xplan.display 为什么查不到刚执行的 sql?
因为 dbms_xplan.display 默认只查 plan_table,而这个表不会自动记录任何执行计划——它得你手动填。很多人执行完 explain plan for ... 就直接调 display,结果返回空或报错 no rows selected。
实操上分两步:先用 EXPLAIN PLAN 把计划写进 PLAN_TABLE,再用 DISPLAY 读出来:
EXPLAIN PLAN SET STATEMENT_ID = 'my_test' FOR SELECT * FROM employees WHERE dept_id = 10;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE', 'my_test', 'ALL'));
-
STATEMENT_ID是可选但强烈建议填的标识符,方便后续定位;不填默认是NULL,但DISPLAY查NULL需显式写成DISPLAY(NULL, NULL, ...),容易出错 - 如果没建过
PLAN_TABLE,运行@?/rdbms/admin/utlxplan.sql(路径因 Oracle 版本和安装路径略有差异) - 注意权限:当前用户需有
SELECT权限(对PLAN_TABLE)和执行DBMS_XPLAN包的权限
怎么查真实执行过的 SQL(不是 EXPLAIN 的预估)?
用 DBMS_XPLAN.DISPLAY_CURSOR,它从共享池(V$SQL_PLAN)里捞最近实际执行过的计划,不需要提前 EXPLAIN。
关键点在于传参要准:
- 第一个参数是
sql_id,从V$SQL里查:SELECT sql_id, sql_text FROM V$SQL WHERE sql_text LIKE '%employees%' - 第二个参数是
child_number,同一sql_id可能有多个子游标(比如绑定变量类型不同),不填默认取 0;不确定时加FORMAT => 'ALLSTATS LAST'看实际 I/O 和行数 - 示例:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abc123xyz456', 0, 'ALLSTATS LAST')); - 如果 SQL 刚执行完就查,但没看到计划,可能是还没入库到
V$SQL_PLAN(极短时间延迟),或被老化淘汰了
FORMAT 参数选哪个才看得清关键信息?
FORMAT 不是越多越好。TYPICAL(默认)会隐藏部分列,比如 BYTES、TEMP_SPACE、OTHER_XML;而 ALL 或 ALLSTATS LAST 才暴露真实代价字段。
- 调试性能问题必用
ALLSTATS LAST:它带运行时统计,含A-Rows(实际返回行数)、Buffers、Reads,和预估的E-Rows对比,一眼看出偏差在哪 -
ADVANCED会输出OTHER_XML,里面含自适应计划决策、动态采样日志等,但需配合DBMS_XPLAN.QUERY_PLANS解析,日常基本用不上 - 别用
BASIC:连Operation和Name都不全,只剩骨架,等于没看
为什么 DISPLAY_CURSOR 返回 ORA-00942 或 no rows?
常见于跨用户或权限不足场景。Oracle 默认只让当前用户查自己的 V$SQL_PLAN 记录,即使 DBA 用户也得显式授权。
- 查别人 SQL 必须有
SELECT_CATALOG_ROLE或直接授SELECT ON V_$SQL_PLAN(注意是V_$视图,不是V$同义词) -
ORA-00942: table or view does not exist往往是因为用了V$SQL_PLAN但没权限,或误写成V$SQL_PLAN_STATISTICS_ALL等不存在的视图名 - 如果 SQL 是在另一个会话执行的,且该会话已断开,对应计划可能已被清除,
DISPLAY_CURSOR就查不到 - 确认是否启用统计收集:
ALTER SESSION SET STATISTICS_LEVEL = ALL;,否则ALLSTATS类 FORMAT 没数据
真正麻烦的不是语法,是共享池生命周期、权限粒度和统计开关这三个点交叉作用——漏一个,计划就“消失”。










