How do I see the Oracle execution plan in SQuirrel SQL? - oracle

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]

Related

Oracle SQL Developer using an always "true" conditional with delete from clause. ("xxx" is null or "xxx" is not null)

I was using today Oracle SQL Developer version 19.2.1.247 and removed couple of rows using the graphical way. I mean, I selected the row and press the red x cross to remove the selected rows.
It worked, all fine. Rows were removed.
However, I took a look to the logs and find out this:
DELETE FROM "DB"."PERSONS" WHERE ROWID = 'AADG' AND ORA_ROWSCN = '5196' and ( "ID" is null or "ID" is not null )
Well, I don't understand the last statement.
"ID" is null or "ID" is not null
To my eyes, apparently, this is always going to be true. I feel curiosity about knowing the reason why this Oracle SQL Developer is adding this. Why is this used? When this statement will not be true?
Probably just an anomaly, but it wont have any impact on the execution (or performance) of the statement. For example, I did:
SQL> create table t as select * from scott.emp;
Table created.
and then deleted a row in SQL Dev, yielding
DELETE FROM "T" WHERE ROWID = 'AAZRaiABAAAA5eLAAL'
AND ORA_ROWSCN = '16330866545209'
and ( "EMPNO" is null or "EMPNO" is not null )
and the optimizer came up with this:
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | DELETE STATEMENT | | 1 | 12 | 1 (0)| 00:00:01 |
| 1 | DELETE | T | | | | |
|* 2 | TABLE ACCESS BY USER ROWID| T | 1 | 12 | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ORA_ROWSCN"=16330866545209)
The redundant predicates were simply ignored.
My table had no indexes or primary keys, so it would appear the simply takes the first column from the table for this predicate.

Explain Plan output in Oracle

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

DRIVING_SITE Oracle Hint with One Remote Table in the script

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' )

How to create EXPLAIN_PLAN table on Amazon RDS database?

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.

Oracle simple Select query optimization

I have below simple dynamic select query
Select RELATIONSHIP
from DIME_MASTER
WHERE CIN=? AND SSN=? AND ACCOUNT_NUMBER=?
The table has 1,083,701 records. This query takes 11 to 12 secs to execute which is expensive. DIME_MASTER table has ACCOUNT, CARD_NUMBER INDEXES. Please help me to optimize this query so that query execution time is under fraction of second.
Look at the predicate information:
--------------------------------------
1 - filter(TO_NUMBER("DIME_MASTER"."SSN")=226550956
AND TO_NUMBER("DIME_MASTER"."ACCOUNT_NUMBER")=4425050005218650
AND TO_NUMBER("DIME_MASTER"."CIN")=00335093464)
The type of your columns is NVARCHAR, but parameters in the query are NUMBERs.
Oracle must cast numbers to strings, but it is sometimes not very smart in casting.
Oracles and fortune-tellers are not always right ;)
These casts prevents the query from using indices.
Rewrite the query using explicit conversion into:
Select RELATIONSHIP
from DIME_MASTER
WHERE CIN=to_char(?) AND SSN=to_char(?) AND ACCOUNT_NUMBER=to_char(?)
then run this command:
exec dbms_stats.gather_table_stats( user, 'DIME_MASTER' );
and run the query and show us a new explain plan.
Would you please do not paste explain plans here, they are unreadable,
please use pastebin instead, and paste only links here, thank you.
Look at this simple example, it shows why you need explicit casts:
CREATE TABLE "DIME_MASTER" (
"ACCOUNT_NUMBER" NVARCHAR2(16)
);
insert into dime_master
select round( dbms_random.value( 1, 100000 )) from dual
connect by level <= 100000;
commit;
create index dime_master_acc_ix on dime_master( account_number );
explain plan for select * from dime_master
where account_number = 123;
select * from table( dbms_xplan.display );
Plan hash value: 1551952897
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 54 | 70 (3)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| DIME_MASTER | 3 | 54 | 70 (3)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("ACCOUNT_NUMBER")=123)
explain plan for select * from dime_master
where account_number = to_char( 123 );
select * from table( dbms_xplan.display );
Plan hash value: 3367829596
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3 | 54 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| DIME_MASTER_ACC_IX | 3 | 54 | 1 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("ACCOUNT_NUMBER"=U'123')
Depending on the cardinality of the columns (Total rows / unique values ) - you can create bitmap indexes on each column. Bitmap indexes are very usefull for and / or operations.
Rule of thumb says that a bitmap index is useful for cardinality of more then 10%.
create bitmap index DIME_MASTER_CIN_BIX on DIME_MASTER (CIN);

Resources