When a SELECT names more than one table, DB2 for z/OS must pick a join method and a join sequence. The optimizer compares nested loop, merge scan, and hybrid join (and how to access each table) using cost. This page explains those methods, how PLAN_TABLE records them, what join predicates do, and how to read the order of tables in EXPLAIN.
Each PLAN_TABLE row is a step. The first table in a query block has METHOD = 0. Each later table is joined with METHOD 1, 2, or 4. A METHOD 3 row is a sort of the composite, not a new table. Independently, ACCESSTYPE on that row tells how that table was read (index, scan, and so on).
| METHOD | Name | Idea |
|---|---|---|
| 0 | First table | Start the composite; access path is on this table only |
| 1 | Nested loop join | For each outer row, find matching inner rows |
| 2 | Merge scan join | Scan both sides in join-column order and merge |
| 3 | Sort | ORDER BY, GROUP BY, DISTINCT, UNION, some predicates — no new table |
| 4 | Hybrid join | Outer scan + inner RID list + list prefetch |
123456789101112SELECT E.EMPNO, D.DEPTNAME FROM HR.EMPLOYEE E JOIN HR.DEPT D ON E.WORKDEPT = D.DEPTNO WHERE E.WORKDEPT = 'A00'; -- EXPLAIN, then: SELECT PLANNO, METHOD, TNAME, ACCESSTYPE, MATCHCOLS, ACCESSNAME, SORTN_JOIN, SORTC_JOIN, JOIN_TYPE FROM PLAN_TABLE WHERE QUERYNO = 2001 ORDER BY QBLOCKNO, PLANNO, MIXOPSEQ;
Join sequence is which table is accessed first, which is joined next, and so on. The optimizer enumerates (or heuristically searches) orders because A-then-B can cost far less than B-then-A. A small department table filtered to one row should usually be outer; a huge employee table should be inner with a matching index on WORKDEPT—not the other way around.
Read sequence from PLANNO within QBLOCKNO. Do not assume FROM-clause order. Views, subqueries, and query rewrite can add extra query blocks; DSN_STRUCT_TABLE helps map those blocks. Parent and child blocks have their own sequences.
After the first table, the “outer” side is the composite—everything joined so far. SORTC_* flags talk about that composite. SORTN_* flags talk about the new (inner) table on this step.
A join predicate relates two tables:
12345678910-- Explicit join predicate in ON SELECT ... FROM HR.EMPLOYEE E INNER JOIN HR.DEPT D ON E.WORKDEPT = D.DEPTNO -- Same relationship in WHERE (older style) SELECT ... FROM HR.EMPLOYEE E, HR.DEPT D WHERE E.WORKDEPT = D.DEPTNO
IBM notes that hybrid and merge scan require join columns. Nested loop does not: if there is no join predicate, nested loop can still pair every outer row with inner rows (a Cartesian nest). That is occasionally intended and often a missing join predicate bug. Always look at METHOD 1 with no join predicate and a huge inner scan as a red flag.
Predicate transitive closure can add implied join or local predicates (if A = B and B = 5, then A = 5). That extra local predicate may enable matching index access on a table that was not written with that literal. DSN_PREDICAT_TABLE shows what the optimizer actually used.
In a nested loop join Db2 scans the composite (outer) once. For each qualifying outer row it searches the new (inner) table for matches and concatenates them. If no inner row matches, inner join drops the outer row; outer join keeps it with nulls as SQL defines.
The inner table is accessed once per qualifying outer row. Therefore nested loop is usually best when:
Nested loop is usually poor when join columns are out of sequence, the inner has no useful index, the index is poorly clustered, and the outer is large—each inner scan or random I/O repeats. Stage 1 and stage 2 predicates still apply during the join; a stage 2 inner predicate evaluated millions of times will show up as CPU, not as ACCESSTYPE R.
Db2 can sort the composite (SORTC_JOIN = Y) so inner index probes follow key order and data I/O becomes more sequential. That sorted nested loop is a hybrid of ideas: still METHOD 1, but with a sort to help clustering. Sparse indexes reduce the need to sort the outer into join order when hashing fits in memory.
123456789-- Typical good nested loop: tiny outer, indexed inner SELECT D.DEPTNAME, E.LASTNAME FROM HR.DEPT D JOIN HR.EMPLOYEE E ON E.WORKDEPT = D.DEPTNO WHERE D.DEPTNO = 'A00'; -- Hope: DEPT is METHOD 0, index on DEPTNO -- EMPLOYEE is METHOD 1, matching index on WORKDEPT
In a merge scan join (sort-merge join) both the composite and the new table are in join-column order. Db2 scans them together like merging two sorted files: advance the side with the smaller key, and concatenate when keys match. Duplicates are handled according to inner versus outer join rules.
Order comes from:
Merge scan is a natural fit when both inputs are large, an equijoin is present, and neither side is a tiny outer with a perfect inner index. You pay sorts (CPU, work files) to avoid nested-loop inner probes. If both clustering indexes already match the join keys, merge can be almost “just two scans.” If both sides sort, watch work-file contention.
Merge scan cannot be used without join columns. Non-equality join predicates generally push you toward nested loop. Highly selective local predicates on one table may still make nested loop cheaper than sorting both large inputs—costing decides.
Hybrid join sits between nested loop and list prefetch. The outer is scanned; inner RIDs are collected via an index, sorted, and the inner table is read with list prefetch. It needs join columns. Use it in your mental model when the inner index is useful for finding rows but not clustered for nested-loop I/O. RID pool failures can undermine it—see the prefetch page.
Join method and table access method are separate knobs:
Always read ACCESSTYPE and MATCHCOLS on each join step, not only METHOD on the second table.
Three-table joins are two steps: join T1 to T2, then join that composite to T3 (or another order). Each step has its own METHOD. A bad second step can dominate even if the first join is perfect.
LEFT/RIGHT/FULL OUTER JOIN set JOIN_TYPE and restrict reorderings: you cannot freely make the preserved table inner if that would drop unmatched rows. Star join (fact plus dimensions) has extra matching rules on the fact index; it is a specialized sequence, not a fourth everyday METHOD value for beginners.
Nested loop is looking up each classmate's phone number one by one in the phone book: fine for three friends, terrible for the whole school if the book is messy. Merge scan is sorting both the class list and the phone book by name and walking down the two lists with a finger on each. Hybrid join is writing every classmate's page number on scrap paper, sorting the page numbers, and fetching those pages in stacks. Join sequence is who you start with—the tiny class list or the giant phone book. Join predicates are the rule “match on last name.”
1. What does PLAN_TABLE METHOD = 0 mean?
2. When is nested loop join usually efficient?
3. What is merge scan join?
4. How do you read join sequence from PLAN_TABLE?
5. Which join methods require join predicates (join columns)?