Every user session on Oracle database will be able to access default table PLAN_TABLE to collect execution plan of a query from EXPLAIN PLAN command. But, how is this table available to all the users in the database and gets empty once you disconnect? Is this table available and created for every user logging into the database or is it a global table and available publicly to access? I am sure that you must have got little excited with these questions and we are going to get answers for many such questions in this blog with the help of a step-by-step analytic approach. In our earlier articles “EXPLAIN PLAN for multiple SQL statements”, “Ways of generating EXECUTION PLAN in Oracle Database” we have clearly understood the usage of PLAN_TABLE to generate execution plan for a query. In this blog, we are going to see what exactly is this PLAN_TABLE and all the concepts around its existence.
Basics:
- Earlier to 11g, consider in 10g we will have to create this default table for EXPLAIN PLAN running utlxplan.sql file from $ORACLE_HOME/rdbms/admin. Let us read this file and understand what exactly is this PLAN_TABLE.
[oracle@PT-DB ~]$ cd $ORACLE_HOME/rdbms/admin/utlxplan.sql
create table PLAN_TABLE (
statement_id varchar2(30),
plan_id number,
timestamp date,
remarks varchar2(4000),
….);
- It has got just one DDL to create PLAN_TABLE in the schema you are connected to when running this SQL file. So it doesn’t actually give us good details of why is this now available in 11gR2(Which I am using). Let us start our analysis with our case study now.
Case study:
- From dba_objects let us understand what is the object type of PLAN_TABLE by connecting to the data base as SYS.
SQL> col OBJECT_NAME for a20
SQL> select object_name,OBJECT_TYPE from dba_objects where object_name=’PLAN_TABLE’;
OBJECT_NAME OBJECT_TYPE
—————- ————————————————
PLAN_TABLE SYNONYM
- It says that PLAN_TABLE is a SYNONYM and not the real name of a table.
- Let us extract the DDL of PLAN_TABLE synonym to check the actual table name.
SQL>select dbms_metadata.get_ddl(‘SYNONYM’,’PLAN_TABLE’,’PUBLIC’) from dual;
CREATE OR REPLACE PUBLIC SYNONYM “PLAN_TABLE” FOR “SYS”.”PLAN_TABLE$”
- Now it is clear that PLAN_TABLE is a PUBLIC synonym of SYS.PLAN_TABLE$ and so it is accessible by all the users.
- But the question still alive that how this table contents are erased every time session gets disconnected. Let us go further into the analysis.
- At this moment, I could recollect the concepts of GLOBAL TEMPORAY TABLES (GTT) which have got the feature of cleaning up the data in the table after the session disconnects. So let us check if SYS.PLAN_TABLE$ is a GTT.
SQL> select table_name,TEMPORARY from dba_tables where table_name=’PLAN_TABLE$’;
TABLE_NAME T
—————————— ———-
PLAN_TABLE$ Y
- There it is!!! We got to know that PLAN_TABLE$ is a GLOBAL TEMPORARY TABLE and PLAN_TABLE is a PUBLIC SYNONYM which is why it is available for all the users to access and data gets erased as soon as session disconnects.
- Having understand the type of the object, let us try to find where exactly the data is temporarily stored until the user session disconnects. To achieve this let me check with the following query.
SQL> select table_name,TEMPORARY,tablespace_name from dba_tables where table_name=’PLAN_TABLE$’;
TABLE_NAME T TABLESPACE_NAME
—————————— ————– —————–
PLAN_TABLE$ Y
- Oops!!! There is not tablespace_name for this object at all. Does it mean that data is not stored in the segments at all? No, GTT data is always stored in the data file segments. But how do we recognize which tablespace segment? From the core concepts of Global Temporary Tables from Oracle document, the default segments used by global temporary tables are from the default temporary tablespace of the user session.
- Let us check if the PLAN_TABLE has some data and parallel check temporary tablespace segment usage.
SQL> select count(*) from plan_table;
COUNT(*)
———-
0
SQL> select USER,BLOCKS from v$tempseg_usage;
no rows selected
- I am going to run EXPLAIN PLAN of a query and re-check the same as above.
SQL> explain plan for select * from v$session;
Explained.
SQL> select count(*) from plan_table;
COUNT(*)
———-
6
SQL> select USER,BLOCKS from v$tempseg_usage;
USER BLOCKS
———————- ———————————–
SYS 128
SYS 128
SYS 128
- Excited!!! This proves that data of PLAN_TABLE is stored in temporary tablespace of the database.
- As we see single table SYS.PLAN_TABLE$ is used by all the concurrent sessions in the database, let us check if data in this table is private to each session.
SYS connection:
SQL> select count(*) from sys.plan_table$;
COUNT(*)
———-
0
Session 1:
SQL> explain plan for select * from v$session;
Explained.
SQL> select count(*) from sys.plan_table$;
COUNT(*)
———-
6
SYS connection:
SQL> select count(*) from sys.plan_table$;
COUNT(*)
———-
0
- This is how GTT tables work, data from the table is bundled to the session which writes the data.
- Unfortunately, there is no method to check which session occupying what space of temporary segments for any Global Temporary Tables.
- Does this table have any indexes created by default? Let us check that if so.
SQL> select index_name,index_type from dba_indexes where TABLE_NAME=’PLAN_TABLE$’;
INDEX_NAME INDEX_TYPE
————– ———————————————————————————-
SYS_IL0000005124C00027$$ LOB
- Which means that this is the index created for LOB columns in the table by default by the database. So PLAN_TABLE$ have a LOB column in it. Apart from that there are no indexes created on this table.
Further interesting questions:
- Will optimizer write an execution plan when you query PLAN_TABLE and if so what access paths it will use?
- Can we gather stats on any Global Temporary Table and how can we verify them?
I will leave these questions to answer yourself by continuing exciting analysis of this case study 🙂
Conclusion:
- PLAN_TABLE is a PUBLIC SYNONYM of SYS.PLAN_TABLE$ Global Temporary Table.
- Data of PLAN_TABLE is stored into temporary tablespace segments.
- Temporary tablespace is not just used for sorting; it is also used by global temporary tablespaces.
- Data of PLAN_TABLE is private to the session itself, even SYS user cannot query all the contents of PLAN_TABLE.
- Default index for CLOB column is created on SYS.PLAN_TABLE$ table.
- Users connected from application or OEM or SQL plus or any other tool will be able to access PLAN_TABLE.
I love to see your comments!
Feel free to give additional information in the comments, that I can validate and include in blog posts or update this as well.
Sridhar kumar sahu
Great explanation regarding plan table .. love it..
Pawan Kumar Yaddanapudi
Thank you Sridhar.
Rajat Samanta
Nicely explained
Pawan Kumar Yaddanapudi
Thanks Rajat
Mitesh Turakhiya
Good Content Pawan Kumar. Keep it up. It is really helpful.
Pawan Kumar Yaddanapudi
Thank you Mitesh 🙂
Ronald
Can you make a video or blog post for virtual catalog like creating, deleting, maintaining catalog and confidentiality???
Pawan Kumar Yaddanapudi
Will mark it up!! Thanks
Karthick
Awesome Explanation .
Gowtham
Why have you stopped posting in 2018 , pls continue we will be always there to watch