How to create EXPLAIN_PLAN table having no access to console? Is there an option to tick somewhere?
I believe you are referring to PLAN_TABLE used in "explain plan" commands. In Oracle 11.2 it's already created by default as a temporary table in the SYS schema (PLAN_TABLE$) with public synonym and privileges to all users.
So "explain plan" should work right out of the box and then you can read the results from the table:
explain plan for select * from dual;
select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------
Plan hash value: 272002086
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
It's a temporary table, so the contents aren't saved between sessions. If for any reason you think you still need a plan table, I think you can create one exactly like the original in your account by using the result of this query:
select dbms_metadata.get_ddl('TABLE','PLAN_TABLE$', 'SYS') from dual;
You'll need to modify the name and owner (remove "SYS." and the "$") and maybe make it a permanent table if that's what you need.
Hope this helps.
Related
I'm trying to get the execution plan for Oracle (11) using SQuirreL SQL 3.6.
I can see an "Explain Plan" tab next to the "Results" tab but it's always empty.
When I clicked on it the first time, I got a dialog asking to create the PLAN_TABLE which worked but the table in the "Explain Plan" tab stays empty.
I tried to add explain plan for before my query but that gave me an Error: ORA-00905: missing keyword
Simple way independent of your SQL client:
EXPLAIN PLAN SET STATEMENT_ID = 'yourTag' into plan_table FOR
select .... your query here ... from tab;
---
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'yourTag','ALL'));
You get the complete execution plan as a result of the query.
The PLAN_TABLE must exists und your user must be granted to read and write to it.
sample output for the query
select * from dual where dummy = 'X';
Plan hash value: 272002086
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS STORAGE FULL| DUAL | 1 | 2 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / DUAL#SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - storage("DUMMY"='X')
filter("DUMMY"='X')
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "DUMMY"[VARCHAR2,1]
I am trying to measure the query execution time in oracle 12c for in-memory database against disc based database. At client side, I am using JDBC to fire the query.
How do I know that whether the query looks for required database in in-memory or in disc? Is there any option that tells the oracle db server that look for the database first into in-memory and then into disc?
How do I know that whether the query looks for required database in in-memory or in disc?
You can see that whether the oracle has looked into the memory or disk for data in the Execution Plan as shown below.
SQL> desc t1
Name Null? Type
----------------------------------------- -------- ----------------------------
COL1 VARCHAR2(20)
COL2 VARCHAR2(20)
SQL> alter table t1 inmemory;
Table altered.
SQL> explain plan for select * from t1;
Explained.
SQL> select * from table(dbms_xplan.display());
Plan hash value: 3617692013
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 0 (0)|
| 1 | TABLE ACCESS INMEMORY FULL| T1 | 1 | 24 | |
------------------------------------------------------------------------
8 rows selected.
SQL> alter table t1 no inmemory;
Table altered.
SQL> explain plan for select * from t1;
Explained.
SQL> select * from table(dbms_xplan.display());
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T1 | 1 | 24 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------
8 rows selected.
Is there any option that tells the oracle db server that look for the database first into in-memory and then into disc?
Oracle Doc says-
INMEMORY_QUERY is used to enable or disable in-memory queries for the entire database at the session or system level. This parameter is helpful when you want to test workloads with and without the use of the In-Memory Column Store (IM column store).
You disable the in-memory query as:
SQL> alter session set inmemory_query = disable;
You give INMEMORY hint to optimizer to look into the memory for the data as shown below.
select /*+ INMEMORY */ * from t1;
I'm not expert on Oracle just started working around. When I execute following queries it gives me output in |(pipeline) format. I want EXPLAIN PLAN output in tabluar or json or xml, etc... Is it possible?
EXPLAIN PLAN FOR SELECT * FROM user_master;
SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY('plan_table'));
Output:
Plan hash value: 3060894046
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 94 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| USER_MASTER | 1 | 94 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------
You can get it in tabular format if you access the PLAN_TABLE directly:
select plan_id,
operation,
options,
cost,
cpu_cost,
io_cost,
temp_space,
access_predicates,
bytes,
object_name,
object_alias,
optimizer,
object_type
from plan_table
start with parent_id is null
connect by prior id = parent_id;
As the plan_table can contain different plans, it's probably better to use an explicit statement id:
explain plan
set statement_id = 'foo'
for
select ...;
and then use that in the select on the plan_table:
select ....
from plan_table
start with parent_id is null and statement_id = 'foo'
connect by prior id = parent_id;
To get this as XML you can use:
select dbms_xplan.display_plan(type => 'xml')
FROM dual
Is there any advantage of using DRIVING_SITE hint when accessing data from only one remote table. The execution plan remains same with and without the hint.
SELECT /*+ DRIVING_SITE(REMOTE_TABLE) */ distinct a.COL1_NB, a.COL2_TX, a.COL3_TX
FROM REMOTE_TABLE#DASH a
WHERE TRUNC(SYSDATE) BETWEEN A.HSTRY_EFCTV_DT AND HSTRY_XPRTN_DT
The Remote_table have close to 2M data and the resultset expected to have around 300K records.
Probably not. If you are only querying objects in the remote database, it is highly unlikely that the optimizer would generate a plan where the local site was the driving site. If you aren't seeing the query plan change, that implies that this query likely isn't one of the rare ones that the optimizer would screw up.
I'd strongly suggest removing the hint.
I have the following query in an Oracle R12 procedure:
SELECT /*+ DRIVING_SITE(FFUSA_MISSING_DOCS) */ *
FROM FFUSA_MISSING_DOCS#EBS_ONBASE FFUSA_MISSING_DOCS
WHERE "Renewal Date" >= DATE '2018-08-01' OR "Renewal Date" IS NULL;
EBS_ONBASE is a database link to MS SQL. I can't get it to filter on the remote database (where equivalent queries take 2 minutes instead of 12+ and return a lot fewer rows). So I personally would strongly suggest keeping the hint and trying to figure out how to get Oracle to listen to you long enough to have them support sending simple filters to remote non-Oracle databases. Here's the explain plan showing how it returns all the data then tries to filter:
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT|
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 195 | 277K| 200 (0)| 00:00:01 | | |
|* 1 | FILTER | | 195 | 277K| 200 (0)| 00:00:01 | | |
| 2 | REMOTE | MISSING_DOCS | | | | | EBS_O~ | R->S |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("Renewal Date" IS NULL OR "Renewal Date">=TO_DATE(' 2018-08-01 00:00:00',
'syyyy-mm-dd hh24:mi:ss'))
Remote SQL Information (identified by operation id):
----------------------------------------------------
2 - SELECT {column list} FROM
"MISSING_DOCS" (accessing 'EBS_ONBASE' )
We do an initial bulk load of some tables (both, source and target are Oracle 11g). The process is as follows: 1. truncate, 2. drop indexes (the PK and a unique index), 3. bulk insert, 4. create indexes (again the PK and the unique index). Now I got the following error:
alter table TARGET_SCHEMA.MYBIGTABLE
add constraint PK_MYBIGTABLE primary key (MYBIGTABLE_PK)
ORA-01652: unable to extend temp segment by 128 in tablespace TEMP
So obviously TEMP tablespace is to small for PK creation (FYI the table has 6 columns and about 2.2 billion records). So I did this:
explain plan for
select line_1,line_2,line_3,line_4,line_5,line_6,count(*) as cnt
from SOURCE_SCHEMA.MYBIGTABLE
group by line_1,line_2,line_3,line_4,line_5,line_6;
select * from table( dbms_xplan.display );
/*
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2274M| 63G| | 16M (2)| 00:05:06 |
| 1 | HASH GROUP BY | | 2274M| 63G| 102G| 16M (2)| 00:05:06 |
| 2 | TABLE ACCESS FULL| MYBIGTABLE | 2274M| 63G| | 744K (7)| 00:00:14 |
-----------------------------------------------------------------------------------------------
*/
Is this how to tell how much TEMP tablespace will be needed for PK creation (102 GB in my case)? Or would you make the estimate differently?
Additional: The PK only exists on the target system. But fair point, so I run your query on target PK:
explain plan for
select MYBIGTABLE_PK
from TARGET_SCHEMA.MYBIGTABLE
group by MYBIGTABLE_PK ;
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (34)| 00:00:01 |
| 1 | HASH GROUP BY | | 1 | 13 | 3 (34)| 00:00:01 |
| 2 | TABLE ACCESS FULL| MYBIGTABLE | 1 | 13 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
So how would I have to read this now?
This is a good question.
First, If you create the following primary key
alter table TARGET_SCHEMA.MYBIGTABLE
add constraint PK_MYBIGTABLE primary key (MYBIGTABLE_PK)
then you should query
explain plan for
select PK_MYBIGTABLE
from SOURCE_SCHEMA.MYBIGTABLE
group by PK_MYBIGTABLE
To get an estimate (make sure you gather stats exec dbms_stats.gather_table_stats('SOURCE_SCHEMA','MYBIGTABLE').
Second , you can query V$TEMPSEG_USAGE to see how much temp blocks were consumed before you got thrown and v$session_longops to see how much of the total process you finished.
Oracle docs suggests creating a dedicated temp tablespace for the process to not disturb any other operations.
Please post an edit if you find a more accurate solution.