Skip to main content

But... we already have tools for explain plan

There are already ways to see execution plan

This is very true. And for day to day use, they are more then sufficient.

But sometimes the tools don't show the functions/conditions correctly.
And some details are never present (e.g. in complex plans with multiple materialized subqueries, it's sometimes impossible to determine from which copy of a table/subquery a column comes).

(And out of scope of this series, you may want to see bind values, or to know which line in the plan you are on = which (copy of) table is oracle just reading.)

Examples in this blog are necessarily simple ones; and in such examples we see cases where the added value of such access to execution plan is not very high. But never forget that this can be extended to much more complex cases.

Existing tools

EXPLAIN PLAN

EXPLAIN PLAN is long time with us. The main problem is that it shows plan for a new parse - and this can be different than what a session is actually executing, as it depends on bind types and lengths, NLS settings, and SQL baselines, many optimizer settings... and every version of Oracle introduces more dynamics and adaptability, making it harder and harder to get exactly the same plan.
On the other hand, EXPLAIN PLAN runs "offline" and thus has time to do more parsing of the plan than other approaches, and thus can parse some cases that other ways cannot. E.g. this output of explain plan won't be shown with dbms_xplan:
filter("Q"."PROD_NAME"= (SELECT LISTAGG(TO_CHAR("PROD_ID"),NULL) WITHIN GROUP ( ORDER BY "PROD_ID") FROM "PRODUCTS" "PRODUCTS")) 
But even explain plan fails sometimes:
filter(INTERNAL_FUNCTION("TIME_ID")=TIMESTAMP' 2000-01-01 00:00:00.000000000')
And in other cases (like the multiple subqueries/tables), it simply cannot show the full info, as the plan table does not allow that level of detail.

dbms_xplan

With dbms_xplan, it is easier to get the right plan, as we can specify an existing plan id, or existing cursor.  But it does not parse some of the more complicated cases - for example the first filter from above is shown as:
filter("Q"."PROD_NAME"=)

v$sql_plan

The output is similar to dbms_xplan. What is nice that this is a v$ view... so it should be backed up by a x$ view, and that should have an address in memory, something we should be able to read from the SGA. Let's have a look.

An example SQL

Our example is based on the sample SH schema, with an added table FOOBAR (id number, key varchar2(30)):

SELECT prod_id, key FROM products CROSS JOIN foobar WHERE prod_id in (143,144,id) and id in (1,2,3);

So let's have a look at the v$sql_plan. This is backed by x$kqlfxpl:

select addr, kqlfxpl_oper, kqlfxpl_oopt from x$kqlfxpl where kqlfxpl_sqlid='b4hdxqwy614fa'
ADDR             KQLFXPL_OPER         KQLFXPL_OOPT
---------------- -------------------- -------------------
00007F9F384F2E68 SELECT STATEMENT
00007F9F384F2C10 NESTED LOOPS
00007F9F384F2990 TABLE ACCESS         FULL
00007F9F384F2698 INDEX                FULL SCAN
The important detail is the ADDR. As we've seen in the previous post, SGA base is 0x60_000_000, but e.g the first ADDR is 
0x7F9_F38_4F2_E68, somewhere very, very far. It's also close to 2^48, the size of current CPU address space (64-bit CPUs use 48-bit address space, to save on the address line cost; it's still more than enough). Process stack tends to grow down from the top of process address space. This indicates that this is process' private stack memory.

The truth is that v$sql_plan does not read the plan directly - instead it is using a helper function to first populate a temporary array, and then to show that array. We thus need to go deeper to get the raw, unparsed execution plan.

Next time we will look where the function gets the data from.

Comments

Popular posts from this blog

ORA-27048: skgfifi: file header information is invalid

I was asked to analyze a situation, when an attempt to recover a 11g (standby) database resulted in bunch of "ORA-27048: skgfifi: file header information is invalid" errors. I tried to reproduce the error on my test system, using different versions (EE, SE, 11.1.0.6, 11.1.0.7), but to no avail. Fortunately, I finally got to the failing system: SQL> recover standby database; ORA-00279: change 9614132 generated at 11/27/2009 17:59:06 needed for thread 1 ORA-00289: suggestion : /u01/flash_recovery_area/T1/archivelog/2009_11_27/o1_mf_1_208_%u_.arc ORA-27048: skgfifi: file header information is invalid ORA-27048: skgfifi: file header information is invalid ORA-27048: skgfifi: file header information is invalid ORA-27048: skgfifi: file header information is invalid ORA-27048: skgfifi: file header information is invalid ORA-27048: skgfifi: file header information is invalid ORA-00280: change 9614132 for thread 1 is in sequence #208 Interestingly, nothing interesting is written to

Multitenant and standby: recover from subsetting

In the previous post we learnt how to exclude a PDB (or a datafile) from the standby database recovery. Of course, that might not be the real end goal. We may just want to skip it for now, but have the standby continue to be up-to-date for every other PDB, and eventually include the new PDB as well. Again, standard Oracle pre-12c DBA knowledge is helpful here. These files are just missing datafiles and thus a backup can be used to restore them. The new 12c features add some quirks to this process, but the base is just sound backup and recovery. Backup So let's start with a proper backup: rman target=/ Recovery Manager: Release 12.1.0.2.0 - Production on Mon Nov 16 12:42:38 2015 Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved. backup database; connected to target database: CDB2 (DBID=600824249) Starting backup at 16-NOV-15 using target database control file instead of recovery catalog allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID=193

Multitenant and standby: subsetting

In the previous post we looked at managing new PDBs added to a standby database, by copying the files to the DR server, as required. However, there is another possible approach, and that is to omit the PDB from the standby configuration altogether. There are two ways of achieving this: 1. Do it the old-school way. A long time before 12c arrived on the scene one could offline a datafile on the standby database to remove it. The same trick is used in TSPITR (tablespace point-in-time recovery), so that you don't need to restore and recover the entire database if you are only after some tablespaces. 2. 12.1.0.2 adds the option to automatically exclude the PDB from standby(s). And 12.2 adds the option to be more specific in case of multiple standbys. For the sake of curiosity I started by setting standby file management to manual again. What I found is that there was very little difference, and the steps to take are exactly the same - it’s just the error message that is slightly