转载: ORACLE-BASE - WITH Clause : Subquery Factoring in Oracle
# Setup
The examples below use the following tables.
1 | -- DROP TABLE EMP PURGE; |
# Subquery Factoring
The WITH
clause, or subquery factoring clause, is part of the SQL-99 standard and was added into the Oracle SQL syntax in Oracle 9.2. The WITH clause may be processed as an inline view or resolved as a temporary table. The advantage of the latter is that repeated references to the subquery may be more efficient as the data is easily retrieved from the temporary table, rather than being requeried by each reference. You should assess the performance implications of the WITH
clause on a case-by-case basis.
This article shows how the WITH
clause can be used to reduce repetition and simplify complex SQL statements. I’m not suggesting the following queries are the best way to retrieve the required information. They merely demonstrate the use of the WITH clause.
Using the SCOTT schema, for each employee we want to know how many other people are in their department. Using an inline view we might do the following.
1 | -- Non-ANSI Syntax |
Using a WITH
clause this would look like the following.
1 | -- Non-ANSI Syntax |
The difference seems rather insignificant here.
What if we also want to pull back each employees manager name and the number of people in the managers department? Using the inline view it now looks like this.
1 | -- Non-ANSI Syntax |
Using the WITH
clause this would look like the following.
1 | -- Non-ANSI Syntax |
So we don’t need to redefine the same subquery multiple times. Instead we just use the query name defined in the WITH
clause, making the query much easier to read.
If the contents of the WITH
clause is sufficiently complex, Oracle may decide to resolve the result of the subquery into a global temporary table. This can make multiple references to the subquery more efficient. The MATERIALIZE
and INLINE
optimizer hints can be used to influence the decision. The undocumented MATERIALIZE
hint tells the optimizer to resolve the subquery as a global temporary table, while the INLINE
hint tells it to process the query inline.
1 | WITH dept_count AS ( |
Even when there is no repetition of SQL, the WITH
clause can simplify complex queries, like the following example that lists those departments with above average wages.
1 | WITH |
In the previous example, the main body of the query is very simple, with the complexity hidden in the WITH
clause.
# MATERIALIZE Hint
The undocumented MATERIALIZE
hint was mentioned above, but there seems to be a little confusion over how it is implemented. We can see what is happening under the covers using SQL trace.
Create a test table.
1 | CONN test/test |
Check the trace file location.
1 | SELECT value |
Trace a statement using the MATERIALIZE
hint.
1 | EXEC DBMS_MONITOR.session_trace_enable; |
The following abbreviated output shows some points of interest in the resulting trace file. Notice the “CREATE GLOBAL TEMPORARY T” and “TABLE ACCESS FULL SYS_TEMP_0FD9D662B_2E34FB” lines. It certainly seems to be using a global temporary table.
1 | ===================== |