Query Execution Plans
When the query optimizer evaluates a query (such as the SQL statements SELECT, INSERT, UPDATE, DELETE, and CREATE TABLE...AS), it generates a QEP showing how the query is executed. Once the QEP has been generated, it can be used one or more times to execute the same query. Because there are often many ways to optimize a given query, choosing the best QEP can have a significant impact on performance.
You can display a diagram or graph of the QEP selected, which can be used to gain insight into how queries are handled by the query optimizer. Knowing how to read and analyze QEPs can allow you to detect, and often avoid, hidden performance problems. After examining a QEP you can, for example, decide that you need to optimize your database to provide the optimizer with better statistics, as described in
Database Statistics.
Examining QEPs can help you understand what is involved in executing complex queries in single-user situations.
Information on a QEP
The information that can appear on a QEP is as follows:
Table or Index Name
Indicates the table on which the query is being run or the secondary index, if any is selected by the query optimizer for execution of the query. This information is provided for orig nodes only (described under Type of Nodes in a QEP below).
Label
Indicates the type of node. For example, Proj-rest identifies a projection-restriction node (described under Type of Nodes in a QEP below).
Storage Structure
Indicates the storage structure in use, as follows, where key is the primary key, and NU indicates that the key structure cannot be used:
B-tree(key|NU)
Hashed(key|NU)
Heap
Isam(key|NU)
Total Number of Pages and Tuples
Indicates the total number of pages involved at the node, and the total number of tuples (rows).
Query Cost Information
Indicates the cumulative amounts of cost that are anticipated at each stage in the execution of the query. This cost is a blend of the CPU consumption and the number of disk I/Os involved in plan execution. The information is shown in the following form:
• Dx estimates the disk I/O cost. x approximates the number of disk reads to be issued.
• Cy estimates the CPU usage, which has been subjected to a formula which turns it into an equivalent number of disk I/Os. y units can be used to compare amounts of CPU resources required.
• Nz is shown for Star databases only. z represents the network cost of processing the query.
Because these values are cumulative up the tree, the top node carries the total resources required to execute the query. The cost involved in executing a specific node is, therefore, the values for that node, minus those of the child node (or both child nodes in the case of a join node).
The QEP graph you see in VDBA indicates both the cumulative cost and the cost for the individual node. For more information, see Viewing QEP Node Information in online help.
View a QEP
In general, it is a good idea to test run a query (that is, view the QEP).
In Director, in the Query tab, click Options, Execution, Advanced, View Query Plan. When you execute the query, the QEP is displayed in the Trace tab.
In VDBA, if you open the SQL Scratchpad window and click Execute QEP, you automatically see the query execution plan in a graphical form.
From a terminal monitor or embedded SQL, you can see the QEP by using the SET QEP statement. On the SET statement, the [NO]OPTIMIZEONLY, [NO]QEP, and JOINOP [NO]TIMEOUT clauses pertain to QEPs. The QEP is displayed in text-only format when using SQL.
Control QEP Generation Using a Environment Variable
To control whether QEPs are generated using an operating system environment variable, issue the following commands:
C shell:
setenv ING_SET "set qep"
Bourne shell:
ING_SET = "set qep"
export ING_SET
Text-Only QEP
In a terminal monitor, a QEP is displayed as a tree, where each node has one or two children:
Parent
/ \
Child Child
/
Parent
/ \
Child Child
Only join nodes have two children. Other nodes have a left child only. Information on node types is provided in
Types of Nodes in a QEP.
The tree is read from bottom to top and from left to right, starting with the child nodes at the bottom, going up to the intermediate child nodes, if any, and finally up to the first parent node:
QEPs as Data Flow Trees
The bottom up approach in the tree diagram mirrors the flow of data during the execution of a query plan.
Rows are read in the leaf nodes of the query plan, WHERE clauses are applied to reduce the number of rows as soon as possible, with qualified rows being passed up through the remaining nodes of the query plan.
Intermediate plan nodes can sort the data or join it to rows from other tables.
Each successive node performs some refinement on the rows received from below. The final result rows emerge from the top of the plan as requested by the query.
Modes for Showing Tree Diagrams
In the SQL Scratchpad window, you can show the tree diagram in one of two modes:
• Preview mode gives you a condensed version of the tree, where you can point to a node to see its detailed information.
• Normal mode displays the detailed information as part of the tree diagram.
Note: A query that has been modified to include views, integrities, and/or grants, is more involved. The QEP diagram for an involved query (as shown by set qep) can be very wide. On a printout, the diagram can even wrap so that similar levels in the tree appear on distinct levels. You can find it easier to read such a QEP if you cut and paste the diagram into the correct levels.
Concise QEP
SET QEP CONCISE displays the QEP in a format suitable for parsing by a program. The format is as follows:
<Query Plan No and timeout details>| {top node [{left child [{left child…}][{right child…}]};
The following example shows a QEP displayed in tree format and concise format.
Tree format
QUERY PLAN 1,1, no timeout, of main query
Hash Join(reltid,
reltidx)
Heap
Pages 1 Tups 91
D20 C41
/ \
Proj-rest Proj-rest
Heap Heap
Pages 1 Tups 177 Pages 9 Tups 1817
D2 C2 D18 C18
/ /
iirelation iiattribute
(r) (a)
cHashed(NU) cHashed(NU)
Pages 18 Tups 177 Pages 132 Tups 1817
Concise format
QUERY PLAN 1,1, no timeout, of main query | {Hash Join(reltid, reltidx) Heap Pages 1 Tups 91 D20 C41 {Proj-rest Heap Pages 1 Tups 177 D2 C2 {iirelation (r) cHashed(NU) Pages 18 Tups 177 }}{Proj-rest Heap Pages 9 Tups 1817 D18 C18 {iiattribute (a) cHashed(NU) Pages 132 Tups 1817 }}};
Graphical QEP
In Director and in VDBA, QEP diagrams appear in the query information pane as a graph.
For a detailed description of each element in the graph, see the online help.
Types of Nodes in a QEP
Each node in a QEP has detailed information associated with it, depending on the type of node.
The types of nodes are as follows:
• Orig (or leaf) node—describes a table
• Proj-rest node—describes the result of a projection and/or WHERE clause restriction applied to a subsidiary node
• Join node—describes a join. One of the following strategies is used:
– Cartesian product
– Full sort merge
– Partial sort merge
– Key and tid lookup joins
– Subquery joins
• Exchange node—describes a point at which separate plan fragments execute concurrently on different threads as part of a parallel query plan
Sort Nodes in a QEP
Many types of nodes can also be shown as sort nodes. A sorting node causes the data to be sorted as it is returned. Any node other than an orig node can appear with a sort indication. A query with a SORT clause has a sort node as the topmost node in the QEP. This type of node displays:
• Total number of pages and tuples
• Query cost information
For a description of each of these parts of the display, see
Information on a QEP.
Sort nodes make use of a sort buffer and so consume primarily CPU resources, requiring disk I/O only when the volume of data to be sorted cannot be accommodated in the sort buffer. The heapsort algorithm is used; it is very fast on both unordered data and data which is nearly sorted.
Non-Join Nodes in a QEP
Types of non-join nodes are as follows:
• Orig
• Projection-restriction
• Exchange
Orig Nodes
Orig nodes are nodes with no children. When reading a QEP, you should first find the orig nodes of the tree. Orig nodes are the most common type of QEP node.
Orig nodes describe a base table or secondary index being accessed from the query. This type of node displays the following:
• Table or index name
• Storage structure
• Total number of pages and tuples
For a description of each of these parts of the display, see
Information on a QEP.
Projection-Restriction Nodes
A projection-restriction (proj-rest) node describes the result of a projection and/or WHERE clause restriction applied to a subsidiary node. It defines how a subsidiary node is to key into the table and what qualification to use on the table. This type of node displays the following:
• A label identifying it as a proj-rest node
• Storage structure (which is usually heap)
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
For a description of each of these parts of the display, see
Information on a QEP.
Proj-rest nodes are used to remove data irrelevant to the query from a table, so that the minimum amount of data is carried around during the execution of the query. Therefore, only those columns referenced in the target list and WHERE clause for a table are projected, and only those rows that satisfy the WHERE clause restrictions are retained for use higher in the plan.
All you see is the amount of disk I/O required to read the appropriate rows from the node below, and that amount depends on what storage structures were used and the number of pages accessed.
Exchange Nodes
Exchange nodes appear in parallel query plans. An exchange node results in one or more threads being spawned to execute the plan fragment beneath the node. It allows different portions of a complex query plan to execute concurrently, reducing the overall elapsed time taken to execute the query. This type of node displays:
• Estimated reduction in execution time due to the presence of the exchange node
• Count of child threads spawned to execute the plan fragment below the exchange node
• PC Join count, the number of join fragments performed by a partition compatible join
Examples of Non-join Nodes
Here are QEP examples that illustrate non-join nodes. The Sample Tables section describes the tables and indexes used in these examples.
Sample Tables
In these examples, the following two tables are used:
1. Table arel(col1, col2, col3):
Name: arel
Owner: supp60
Created: 26-oct-1998 08:50:00
Location: ii_database
Type: user table
Version: II2.5
Row width: 413
Number of rows: 156
Storage structure: hash
Duplicate Rows: allowed
Number of pages: 70
Overflow data pages: 6
Column Information:
Column Key
Name Type Length Nulls Defaults Seq
col1 integer 4 yes no 1
col2 integer 4 yes no
col3 varchar 400 yes no
Secondary indexes: aindex (col2) structure: isam
2. Table brel(col1,col2):
Name: brel
Owner: supp60
Created: 26-oct-1998 08:53:00
Location: ii_database
Type: user table
Version: II2.5
Row width: 10
Number of rows: 156
Storage structure: isam
Duplicate Rows: allowed
Number of pages: 3
Overflow data pages: 1
Column Information:
Column Key
Name Type Length Nulls Defaults Seq
col1 integer 4 yes n 1
col2 integer 4 yes no
Secondary indexes: none
Primary Key Lookup
This is an example of a simple primary key lookup. The QEP is shown below for the following SQL query:
select col1, col2 from arel
where col1 = 1234
order by col2;
QUERY PLAN 3,1, no timeout, of main query
Sort Keep dups
Pages 1 Tups 1
D1 C0
/
Proj-rest
Sorted(col1)
Pages 1 Tups 1
D1 C0
/
arel
Hashed(col1)
Pages 70 Tups 156
Reading this QEP diagram from bottom to top, Hashed(col1) means the row is being read through the index to return only those rows for which “col1 = 1234,” as opposed to Hashed(NU) where NU indicates that the key structure cannot be used and all rows are returned. The projection-restriction node selected the rows matching the where constraint and removed superfluous columns. The final sort node reflects the SORT clause on the query.
Select on a Non-Keyed Field
The following is an example of a select on a non-keyed field. The QEP is shown below for the following SQL query:
select col1, col2 from arel
where col3 = 'x'
order by col1;
QUERY PLAN 3,1, no timeout, of main query
Sort Keep dups
Pages 1 Tups 1
D9 C0
/
Proj-rest
Heap
Pages 1 Tups 1
D9 C0
/
arel
Hashed(NU)
Pages 70 Tups 156
In this example the Hashed(NU) implies that the table had to be scanned (that is, all 70 pages had to be visited). Without optimization statistics, the query optimizer uses a best guess approach (1% for equalities and 10% for non-equalities).
The query optimizer considers disk read-ahead or group reads when performing scans of tables—although 70 pages of data have to be read to scan arel, the estimated disk I/O value is only nine reads (D9) due to this effect. The query optimizer assumes a typical read-ahead of eight pages when performing scans, so here 70/8 reads generates an estimate of nine disk operations.
Join Nodes in a QEP
There is an inner and an outer tree beneath every join node, which function similarly to an inner and outer program loop. By convention, the left-hand tree is called the outer tree, and the right-hand tree is called the inner tree.
There are several types of join nodes, described individually below, but the joining method is the same: for each row from the outer tree, there is a join to all the rows that can possibly qualify from the inner tree. The next row from the outer tree is processed, and so on.
Any join node can have outer join information if an outer join is present.
Cartesian Product Node
The Cartesian product, or cart-prod, strictly follows the unoptimized join model, with each row in the outer node compared to all rows from the inner node. This does not mean that all rows are read, only that all rows that satisfy the conditions of the query are compared.
A typical abbreviated example of a QEP diagram involving a cart-prod is shown below:
Cart-Prod
/ \
proj-rest table
/
table
This node is displayed with the following information on a QEP diagram:
• A label identifying it as a cart-prod join node, along with the column(s) on which processing is done
• If an outer join has been requested, one of the following labels indicating the type of join:
[LEFT JOIN]
[FULL JOIN]
[RIGHT JOIN]
• Storage structure (which is usually heap)
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
The cart-prod is most frequently observed in disjoint queries (that is, when use of correlation variables and table names are mixed in the query). However, the following cases can also generate cart-prods, without adversely affecting performance:
• Queries involving ORs that can usually be decomposed into a sequence of smaller queries
• No join specification (a disjoint table or no WHERE clause, so that there is no relationship between the two tables)
• Small tables or amounts of data
• Non_equijoins, such as a query with the following WHERE clause:
where r1.col1 > r2.col2
Cart-prods are sometimes associated with substantial estimates for disk I/O usage and affect performance adversely.
This example shows a QEP diagram with a cart-prod join node resulting from the following simple disjoint query:
select arel.col1 from arel, arel a
where a.col1 = 99;
QUERY PLAN 7,1, no timeout, of main query
Cart-Prod
Heap
Pages 1 Tups 243
D9 C4
/ \
Proj-rest Proj-rest
Sorted(NU) Heap
Pages 1 Tups 2 Pages 1 Tups 156
D1 C0 D8 C1
/ /
arel arel
Hashed(col1) Hashed(NU)
Pages 70 Tups 156 Pages 70 Tups 156
Full Sort Merge Node
The full sort merge (FSM) is a more optimal join: it typically joins the inner and outer subtrees with many fewer comparisons than the cart-prod requires. This is done by assuring that both subtrees are sorted in the order of the join columns. If one or the other is not already sorted (for example, by being read from a B-tree index constructed on the join columns), the query plan can include a sort to put the rows in the correct order. This allows the rows of the outer subtree to be joined to the matching rows of the inner subtree with one pass over each. The inner subtree is not scanned multiple times, as with the cart-prod join.
A typical abbreviated example of a QEP diagram involving an FSM is shown below:
join
/ \
sort sort
/ /
proj-rest proj-rest
/ /
table table
This node is displayed with the following information on a QEP diagram:
• A label identifying it as an FSM join node, along with the column(s) on which join processing is done
• If an outer join has been requested, one of the following labels indicating the type of join:
[LEFT JOIN]
[FULL JOIN]
[RIGHT JOIN]
• Storage structure (which is usually heap) or a list of sort columns if the data is being sorted
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
The FSM is most common when a “bulk” join takes place with no row restrictions on either table involved in the join, as with a SELECT statement of the following form:
select * from r1, r2 where r1.joincol = r2.joincol;
This example shows a QEP diagram with an FSM join node resulting from such a bulk join:
select a.col2, b.col2 from arel a, brel b
where a.col1 = b.col1;
QUERY PLAN 5,1, no timeout, of main query
FSM Join(col1)
Heap
Pages 1 Tups 156
D9 C40
/ \
Proj-rest Proj-rest
Sorted(eno) Sorted(eno)
Pages 1 Tups 156 Pages 1 Tups 156
D8 C1 D1 C1
/ /
arel brel
Hashed (NU) Isam (NU)
Pages 70 Tups 156 Pages 3 Tups 156
Partial Sort Merge Node
The partial sort merge (PSM) is a cross between a full sort merge and a cart-prod. The inner tree must be in sorted order. The outer tree can be sorted or partially sorted. The outer tree in PSM scenarios can always be derived from an ISAM table. Comparisons proceed as for the full sort merge until an outer value is found to be out of order. At that point the inner loop is restarted. Because ISAM tables are reasonably well ordered (depending on how many rows have been added because the last reorganization), the number of inner loop restarts is typically small.
A typical abbreviated example of a QEP diagram involving a PSM is shown below:
Join
/ \
proj-rest sort
/ /
table proj-rest
/
table
This node is displayed with the following information on a QEP diagram:
• A label identifying it as a PSM join node, along with the columns on which processing is done
• If an outer join has been requested, one of the following labels indicating the type of join:
[LEFT JOIN]
[FULL JOIN]
[RIGHT JOIN]
• Storage structure (which is usually heap)
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
The following example shows a QEP diagram with a PSM join:
select a.col2, b.col2 from arel a, brel b
where a.col1 = b.col2;
QUERY PLAN 6,1, no timeout, of main query
PSM Join(col1)
Heap
Pages 1 Tups 156
D9 C26
/ \
Proj-rest Proj-rest
Heap Sort on(col1)
Pages 1 Tups 156 Pages 1 Tups 156
D1 C1 D8 C1
/ /
brel arel
Isam(col2) Hashed(NU)
Pages 3 Tups 156 Pages 70 Tups 156
Hash Join Node
The hash is an optimized join that replaces the FSM join when one or both subtrees must be sorted. It functions by loading the rows of one subtree into a memory resident hash table, keyed on the values of the join columns. The rows of the other subtree are hashed on their join key values into the hash table, allowing very efficient matching of joined rows. By avoiding the sort(s) of the FSM join, the hash join can be much more efficient.
A typical abbreviated example of a QEP diagram involving a hash join is shown below:
Join
/ \
proj-rest proj-rest
/ /
table table
This node is displayed with the following information on a QEP diagram:
• A label identifying it as a hash join node, along with the columns on which join processing is done
• If an outer join has been requested, one of the following labels indicating the type of join:
[LEFT JOIN]
[FULL JOIN]
[RIGHT JOIN]
• Storage structure (which is usually heap) or a list of sort columns if the data is being sorted
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
Like the FSM join, the hash join is most common when a bulk join takes place with no row restrictions on either table involved in the join, as with a SELECT statement of the following form:
select from r1,r2 where r1.joincol= r2.joincol;
This example shows a QEP diagram with hash join node resulting from such a bulk join:
select a.col2, b.col2 from arel a, brel b
where a.col1 = b.col2;
QUERY PLAN 1,1, no timeout, of main query
HASH Join(col1)
Heap
Pages 1 Tups 156
D9 C40
/ \
Proj-rest Proj-rest
Heap Heap
Pages 1 Tups 156 Pages 1 Tups 156
D8 C1 D1 C1
/ /
arel(a) brel (b)
Hashed (NU) Isam (NU)
Pages 70 Tups 156 Pages 3 Tups 156
Key and Tid Lookup Join Node
In key and tid lookup joins, the outer and inner data set is not static. For each outer row, the join selects values and forms a key to search in the inner join. A key lookup join uses keyed access through the structure of the inner table or index, and a tid lookup join uses the tuple identifier (tid) value.
A typical abbreviated example of a QEP diagram involving this type of join is shown below:
Join
/ \
sort btree (or hash or isam)
\
proj-rest
\
table
This node is displayed with the following information on a QEP diagram:
• A label identifying it as a key (K) or tid (T) lookup join, along with the column(s) on which processing is done
• If an outer join has been requested, the following label indicating the type of join:
[LEFT JOIN]
• Storage structure (which is usually heap)
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
This case is seen most frequently where the outer subtree proj-rest returns few rows, so it is faster to do a keyed lookup (on an ISAM, hash, or B-tree table) than any of the sort merge operations.
The following example shows a QEP diagram with a key lookup join:
select b.col1, b.col2, a.col2
from arel a, brel b
where a.col3 = 'x' and a.col1 = b.col1;
K Join(col1)
Heap
Pages 1 Tups 2
D3 C0
/ \
Proj-rest brel
Heap Isam(col1)
Pages 1 Tups 2 Pages 3 Tups 156
D1 C0
/
arel
Hashed(NU)
Pages 70 Tups 156
In the next example of a tid lookup join, access to the base table is through the secondary index, and proj-rest collects tids for sorting. The tids are used for a direct tid lookup in the base table. Therefore, the storage structure of the base table is NU:
select a.col1, a.col2 from arel a
where a.col2 = 99
order by a.col2;
Sort(col2)
Pages 1 Tups 1
D4 C1
/
T Join(tidp)
Heap
Pages 1 Tups 1
D4 C0
/ \
Proj-rest arel
Sort on(tidp) Hashed(NU)
Pages 1 Tups 1 Pages 70 Tups 156
D2 C0
/
aindex
Isam(col2)
Pages 2 Tups 156
Subquery Join Node
The subquery join is specific to SQL because SQL allows subselects as part of a query. These nodes join rows from a query to matching rows of a contained subselect, thus allowing the subselect restrictions on the query to be evaluated.
A typical abbreviated example of a QEP diagram involving a subquery join is shown below:
SE join
/ \
proj-rest Tn
/
table
In this diagram, Tn identifies the QEP constructed to evaluate the subselect.
This node is displayed with the following information on a QEP diagram:
• A label identifying it as a subquery (SE) join, along with the column(s) on which processing is done
• Storage structure (which is usually heap)
• Total number of pages and tuples
• Query cost information
• Optionally, sort information (whether the data produced by this node is already sorted or requires sorting)
The following example shows a QEP diagram with a subquery join:
select * from arel a
where a.col2 = (
select col2 from brel b
where a.col1 = b.col1)
and col1 = 5;
QUERY PLAN 3,1, no timeout, of T1
Proj-rest
Heap
Pages 1 Tups 1
D1 C0
/
brel
Hashed(col1)
Pages 3 Tups 156
QUERY PLAN 4,2, no timeout, of main query
SE Join(col1)
Heap
Pages 1 Tups 1
D2 C0
/ \
Proj-rest T1
Heap Heap
Pages 1 Tups 1 Pages 1 Tups 1
D1 C0
/
arel
Hashed(col1)
Pages 70 Tups 156
In the QEP pane of the SQL Scratchpad window in VDBA, these two QEPs are shown in separate tabs.
Subquery joins are reasonably expensive because the subselect must be executed once for each row of the outer subtree. The query optimizer contains logic to flatten various types of subselects into normal joins with the containing query. This allows more optimal joins to be used to evaluate the subselect.
As an example of the subselect flattening enhancement features of the query optimizer, consider the following subselect:
select r.a from r where r.c =
(select avg(s.a) from s
where s.b = r.b and r.d > s.d);
Instead of two scans of table r, the query optimizer has eliminated a scan of table r by evaluating the aggregate at an interior QEP node. The QEP appears similar to the previous example:
QUERY PLAN 7,1, no timeout, of main query
Hash Join(b)
avg(s.a)
Heap
Pages 2 Tups 359
D133 C171
/ \
Proj-rest Proj-rest
Sorted(b) Heap
Pages 1 Tups 359 Pages 40 Tups 359
D65 C112 D32 C3
/ /
r s
Btree (b,c) Hashed(NU)
Pages 44 Tups 359 Pages 44 Tups 359
Multiple Query Execution Plans
The query optimizer can generate multiple QEPs if the query includes any of the following objects:
• SQL subqueries (in, exists, all, any, and so on.)
• SQL UNION / INTERSECT / EXCEPT clause
• SQL GROUP BY clause
• Views that need to be materialized
As an example of multiple QEPs, consider the processing of a view on a union. The following statement creates the view:
create view view1 as
select distinct col1 from arel
union
select distinct col2 from arel;
There are two selects, designated #1 and #2 in their respective QEPs below. Now consider the query optimizer action in evaluating the following query:
select * from view1;
This generates three QEPs, which are shown in order in the example QEP diagrams that follow:
1. The first select in the union
2. The second select in the union
3. Main query—the merged result of the two unioned selects
QUERY PLAN of union view T0
Sort Unique
Pages 1 Tups 156
D1 C10
/
Proj-rest
Heap
Pages 1 Tups 156
D1 C0
/
aindex
Isam(col2)
Pages 2 Tups 156
QUERY PLAN of union subquery
Sort Unique
Pages 1 Tups 156
D4 C10
/
Proj-rest
Heap
Pages 1 Tups 156
D4 C0
/
arel
Hashed(NU)
Pages 70 Tups 156
QUERY PLAN of main query
Sort Unique
Pages 1 Tups 156
D19 C20
/
Proj-rest
Heap
Pages 1 Tups 156
D12 C11
/
T0
Heap
Pages 1 Tups 156
More Complex QEPs
The previous series of QEPs on the different classes of joins involved only two tables. More complex QEPs involving joins with three or more tables can be read as a sequence of two-table joins that have already been described, with the query optimizer deciding what is the optimal join sequence. The key to understanding these complex QEPs is recognizing the join sequences and the types of joins being implemented.