Skip to main content

Column projections

The lower half of the plan

In the previous part, we've seen the data behind the execution plane table, i.e. all the operations, their cost, and the tree structure of the plan. Although interesting to investigate, it's all already available in the dbms_xplan output. Although possibly you can find cases when it does, perhaps with some more complex parallel queries, partitioning and so on.

The more complex part is the "lower half" of the plan, i.e. the column projections, filters and access predicates. These can contain arbitrary operations/functions and it's also here where we can follow where a value comes from, starting from a single table, going through joins, aggregations, set functions and so on, up to the level where is it used (be it top-level column projection = in the select output, or as a filter or access predicate).

In this blog post, let's look at the column projections. In other words, what columns are shown in the resulting select, as well as every step of the execution plan.

Execution plan tree

Obviously, the execution plan is a tree - each row has a depth and exactly one parent (except for the top one, of course). Usually there is just one or two children - but in general, there can be more, for example with UNIONs.

When looking around  kxscio, we nodes of a tree at 0x320. We see a list of pointers there - and if we follow them, we again see row id, and the pointers form a structure:
(Obviously having a more complex plan would show a more complex tree, making the following insights more obvious.)

It might be a little surprising that we always have just one child, and then a pointer to the next sibling... but this is actually a very standard way how to convert an arbitrary tree to a binary tree.

Also if we try some other examples, we may find that the tree has extra nodes, not just those listed at 0x320. These are part of the tree structure, have row id of -1, and look like any other, valid, tree entry. Apparently sometimes Oracle wants/needs to describe intermediate steps in column projections. The only lesson is that we really need to start at the root (first entry) and traverse the tree, in order to see all the nodes.

Columns

The tree nodes have more info than just the pointers in the tree structure. Just the next pointer point to something interesting:
0000000 0000000000010002 0000000000000000 
0000020 0000000065fa2ac8 0000000065fa2190

0000000 0000000000010002 0000000000000000
0000020 0000000065fa2bc8 0000000065fa2ac8

0000000 0000000000010001 0000000000000000
0000020 0000000065fa2190

Well, we actually need to follow the pointers one more time, for example the first ones:
0000000: 0b 00 00 00 01 01 00 00 00 00 00 00 1e 00 00 00 
0000010: 69 03 01 00 00 00 00 00 20 00 00 00 d8 02 00 00
...
0000050: 90 2a fa 65 00 00 00 00

0000000: 0b 00 00 00 02 01 04 00 00 00 00 00 16 00 00 00
0000010: 06 00 00 00 00 00 00 00 20 00 00 00 d8 03 00 00
...
0000050: 58 21 fa 65 00 00 00 00

Hmm... still not convincing. Note that we are looking at the first row, which column projections are "FOOBAR"."KEY"[VARCHAR2,30], "PRODUCTS"."PROD_ID"[NUMBER,22]. The datatypes are 01 and 02 (again, it's better to use something more unique, like INTERVALs... the numbers are the Oracle internal codes, same as what you for example see in 10046 trace when looking at binds). The lengths are 0x1e and 0x16 and we indeed see them here!

The data at 0x50 are actually ordinary pointers - it's a reminder that we are working on little endian architecture and it makes a difference if we look at the data as bytes or as 8-byte chunks. If this is not obvious to you, I recommend stopping here for a while and reading - and understanding - wikipedia explanation. This switching back and forth between byte output and 64-bit pointers is something one has to do automatically, almost at every dump.

0000000 0000000000000000 0000000065fa2130
0000020 0000000065fa2108

And following two more pointers, we arrive at names of the table and the column! (Again, it's useful to be able to spot ASCII values in hex, in order to know when to switch to text output.)
0000000065fa2130
1900 0000 0800 5052 4f44 5543 5453 0000  ......PRODUCTS..
0000000065fa2108
0000 0000 0700 5052 4f44 5f49 4400 0000  ......PROD_ID...

In other test cases, we'd see that even the first pointer might be not null and point to schema name. Also we would confirm that the 08 and 07 are lengths of the name strings.

Summary

Now we know where to find the plan as a tree - and we can even see the columns, their datatypes, lengths and which table they come from. Next time we will look at the filters and predicates - and that there is more structure to all these than meets the eye at first.

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