Oracle Subquery Factoring
Question:
I hear that subquery factoring is a good
replacement for global temporary tables but I don’t know the
syntax.
What is subquery factoring and what is the
syntax for subquery factoring?
Answer:
A more common name for subquery factoring is the SQL WITH clause, an
ANSI-99 standard keyword.
The main purpose of
Oracle subquery factoring is to simplify complex SQL.
Subquery factoring simplifies complex SQL by
materializing complex SQL in much the same way as global temporary
tables.
Also, starting in 11g R2, we see the new
recursive subquery factoring using the
SQL WITH clause.
First, review these notes to understand how
powerful subquery factoring for pre-aggregating and simplifying
complex SQL queries:
****************************
Question:

Although there is an index starting with
record_type, there can be many millions of rows satisfying the
record_type 'PE01'. As a result of Oracle subquery factoring, full table
scans are performed on the temporary table as follows:

My question is this: Is it possible to get it to
create and use an index instead of full-scanning
SYS_TEMP_0FD9D6608_37E723F9 twice, as a result of Oracle subquery
factorying? That itself could get huge, as there are only a limited
number of codes available in record_type and PE01 is likely to be the
most common, accounting for about a quarter to one-half of the rows in
addl_field_details.

The same POC query without Oracle subquery factoring looks like
this:

and on the same database the POC query without
Oracle subquery factoring performs like this:

Is there a better way for me to optimize this to
avoid the full-scans caused by the Oracle subquery farctoring?
Answer:
First, to better understand Oracle subquery factoring please review this
great excerpt from the book "Advanced SQL Programming" on Oracle
subquery factoring:
In the past I've replaced WITH queries with global
temporary tables because you can create indexes on them and avoid some
of the slowdown associated with Oracle subquery factoring.
See my notes on tuning SQL with global temporary tables here.
Let's take a look at an example tuning SQL with global
temporary tables to avoid Oracle subquery factoring:
Say we want to create a report of the total counts of
tables and indexes in the database. This is a very useful report for the
DBA to ensure that no new objects have migrated into the production
environment. We could also see the total bytes for all tables and
indexes and the size change over the past week.
This would be a very sophisticated DBA report, and one
that could run for many hours without the use of temporary tables
because of Oracle’s use of Oracle subquery factoring. However, with the
use of temporary tables, the table and index counts can be summarized
and saved in the temp tables to avoid Oracle subquery factoring. We also
use the same technique to sum the number of bytes in all tables and
indexes into temporary tables, and then quickly interrogate the summary
tables for total sizes of our database, once again avoiding Oracle
subquery factoring.
To avoid Oracle subquery factoring you could create a
report generation SQL script. The code would compute the date ranges and
computes the total table and index counts and bytes. An example is shown
below:

The above example would allow you to avoid the slow
down caused by Oracle subquery factoring.
You can also parallelize the full-scan, if you
determine that the FTS is legitimate, this would reduce the impact of
Oracle subquery factoring.
If I were tuning this, I would test it
with plain CTAS and force index usage.