首页 » ORACLE, ORACLE [C]系列 » 细说“Error: cannot fetch last explain plan from PLAN_TABLE”

细说“Error: cannot fetch last explain plan from PLAN_TABLE”

前几日有位小兄弟问为什么有时使用explain plan for  …..,   然后用dbms_xplan.display查看执行计划, 有时会提示“Error: cannot fetch last explain plan from PLAN_TABLE” 错误? 其实这个问题在Oracle 12c 以后应该基本不存在,因为这是explain plan一种悄悄的行为变化。

Plan_table

explain plan for 把会SQL的执行计划insert 到一个plan_table的对象中,用dbms_xplan.display可以查看执行计划,也可以手动拼SQL检查, 在老版本中PLAN_TABLE是有utlxplan.sql脚本创建,Oracle 8i后引入的全局临时表后,PLAN_TABLE是有plublic synonym指向sys.PLAN_TABLE$的全局临时表(Global Temporary Table)。

因为当oracle检查同名对象时先是当前schema然后在public synonym,当用户下也有PLAN_TABLE表时,并且使用了set current_schema, explain plan for 生成执行计划,在12c之前版本中使用dbms_xplan.display常常会遇到“Error: cannot fetch last explain plan from PLAN_TABLE”错误。

Demo

通常当我们优化SQL时,对于SQL文本中表名前没有带owner时,为不了修改SQL文本,而是直接alter session set current_schema=xxx的形式来防止相关对象不存在。下面我演示一下这种形为。

— Orace 11g and older

SQL> conn / as sysdba

SQL> explain plan set statement_id='anbob1' for 
  2  select sysdate from dual;

Explained.

SQL> @x2

PLAN_TABLE_OUTPUT                                                                               
-------------------------------------------------------------------------------------------------
Plan hash value: 1546270724                                                                     
																								
-----------------------------------------------------------------                               
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |                               
-----------------------------------------------------------------                               
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |                               
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |                               
-----------------------------------------------------------------                               

8 rows selected.

SQL> select statement_id,plan_id,operation,options,object_name,object_alias from sys.plan_table$ where statement_id='anbob1';

STATEMENT_ID            PLAN_ID OPERATION                      OPTIONS       OBJECT_NAME                    OBJECT_ALIAS
-------------------- ---------- ------------------------------ ------------- ------------------------------ -----------------
anbob1                    14618 SELECT STATEMENT                            
anbob1                    14618 FAST DUAL                                                                   DUAL@SEL$1

SQL> alter session set current_schema=ANBOB;

Session altered.

SQL> explain plan set statement_id='anbob2' for 
  2  select sysdate from dual;

Explained.

SQL> @x2

PLAN_TABLE_OUTPUT                                                 
---------------------------------------------------------------------------------------------------------------
Error: cannot fetch last explain plan from PLAN_TABLE             

Note:
x2脚本是TanelPoder的脚本包,实际调用的是dbms_xplan.display, 上面显示了set current_schema=anbob后就无法显示了,下面我们查查explain plan把执行计划写进了哪里?

SQL> @o %.plan_table

owner                     object_name                    object_type        status           OID      D_OID CREATED           LAST_DDL_TIME
------------------------- ------------------------------ ------------------ --------- ---------- ---------- ----------------- -----------------
PUBLIC                    PLAN_TABLE                     SYNONYM            VALID           5127            20141230 17:30:24 20141230 17:30:24
ANBOB                      PLAN_TABLE                     TABLE              VALID        8944840    8944840 20160104 08:55:43 20160104 08:55:43
SYS                       PLAN_TABLE$                    TABLE              VALID           5124            20141230 17:30:24 20141230 17:30:24

14 rows selected.

SQL> @syn plan_table

OWNER                          SYNONYM_NAME                   TABLE_OWNER                    TABLE_NAME                     DB_LINK
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
PUBLIC                         PLAN_TABLE                     SYS                            PLAN_TABLE$

SQL> select statement_id,plan_id,operation,options,object_name,object_alias from ANBOB.plan_table where statement_id='anbob2';

no rows selected

SQL> select statement_id,plan_id,operation,options,object_name,object_alias from sys.plan_table$ where statement_id='anbob2';

STATEMENT_ID     PLAN_ID OPERATION                      OPTIONS      OBJECT_NAME      OBJECT_ALIAS      
--------------- -------- ------------------------------ ------------ ---------------- ------------------
anbob2             14619 SELECT STATEMENT                                                               
anbob2             14619 FAST DUAL                                                    DUAL@SEL$1        

Note:
执行计划insert 到了connect user ,而不是current_schema user, 所以无法从current_schema中plan_table table中显示执行计划。

解决当然简单了,删除掉不需要的PLAN_TABLE 表。

SQL> drop table anbob.plan_table;

# oracle 12c and beyond

sqlplus / as sysdba
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production


SQL> alter session set current_schema=ANBOB;
Session altered.

SQL> explain plan set statement_id='anbob2' for 
  2  select sysdate from dual;
Explained.

SQL> @x2
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1388734953

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------
Note
-----
   - 'PLAN_TABLE' is old version

12 rows selected.

SQL> select statement_id,plan_id,operation,options,object_name,object_alias from ANBOB.plan_table where statement_id='anbob2';

STATEMENT_ID                      PLAN_ID OPERATION                      OPTIONS                                                                                                                                                                                                                                                         OBJECT_NAME                    OBJECT_ALIAS
------------------------------ ---------- ------------------------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------ -----------------------------------------------------------------
anbob2                               2286 SELECT STATEMENT
anbob2                               2286 FAST DUAL                                                                                                                                                                                                                                                                                                                     DUAL@SEL$1

SQL> select statement_id,plan_id,operation,options,object_name,object_alias from sys.plan_table$ where statement_id='anbob2';
no rows selected

SQL> drop table ANBOB.plan_table;
Table dropped.

SQL> explain plan set statement_id='anbob3' for 
  2  select sysdate from dual;
Explained.

SQL> @x2

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1388734953

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

8 rows selected.
SQL> select statement_id,plan_id,operation,options,object_name,object_alias from sys.plan_table$ where statement_id='anbob3';

STATEMENT_ID                      PLAN_ID OPERATION                      OPTIONS                                                                                                                                                                                                                                                         OBJECT_NAME                                                                                                                      OBJECT_ALIAS
------------------------------ ---------- ------------------------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
anbob3                               2287 SELECT STATEMENT
anbob3                               2287 FAST DUAL       

Note:
在12c, 18c , 19c版本中如果CURRENT_SCHEMA中有同名的PLAN_TABLE,explain plan for 会写入到current_schema而不是connect user(与11g及之前的版本不同),所以dbms_xplan.display一样也可以显示执行计划,只是会显示”‘PLAN_TABLE’ is old version”字样,同样在新版本中默认也不会再新用户下创建PLAN_TABLE, 只有原来的版本升级上来的情况存在,但依旧不会影响显示执行计划,所以可以安装放心删除用户schema中PLAN_TABLE,但是注意在删除PLAN_TABLE前确认不被业务应用所使用。

 

打赏

, ,

对不起,这篇文章暂时关闭评论。