|
Therefore, it is very important that:
|
|
for ( each tuple s ∈ S ) do { for ( each tuple r ∈ R ) do { if ( r(Y) == s(Y) ) { output (r, s); } } } |
Worst case performance:
# Disk I/O = T(S) × T(R) |
Advantage:
|
|
Open( ) { R.Open( ); S.Open( ); s = S.getNext(); // s = current tuple of S } |
Graphically:
Note:
|
getNext( ) algorithm in pseudo code:
/* ------------------------------------------------------------------ getNext( ): output the next (just 1 !!!) tuple in the join R ⋈ S ----------------------------------------------------------------- */ getNext( ) { /* ============================================================== Note: s already has the current (next ?) tuple of relation S ============================================================== */ while ( true ) { // Loop exits when: // 1. we found a tuple ∈ R that joins with s // 2. R ⋈ S is done (returns NotFound) /* ================================================= Get the next tuple r ∈ R to Join ================================================ */ r = R.getNext(); // Get next tuple in R to perform Join if ( r == NotFound ) { /* --------------------------------------------------- Tuple s has joined with every tuple ∈ R Use next tuple ∈ S in the Join --------------------------------------------------- */ s = S.getNext( ); if ( s == NotFound ) { /* *********************************** We have processed the last tuple ∈ S ********************************** */ return NotFound; // Done !!! } /* =========================================== We have a new tuple s ∈ S Restart R from the beginning =========================================== */ R.Close(); // Close first R.Open( ); // Reset R to beginning r = R.getNext(); // Get current tuple in R } /* ================================================= When we reach here, we have: s = current tuple in S for the Join operation r = current tuple in R for the Join operation ================================================ */ if ( r(Y) == s(Y) ) { return (r,s); // Return next tuple of Join } // Repeat and try the next tuple in R } } |
Close( ) { R.Close( ); S.Close( ); } |
|
|
|
while ( S ≠ empty ) { Read M - 1 blocks of S: organize these tuples into a search structure (e.g., hash table)' Rewind R; while ( R ≠ empty ) { Read 1 block (b) of R; for ( each tuple t ∈ block b ) do { Find the tuples s1, s2, ... of S (in the search structure) that join with t Output (t,s1), (t,s2), ... } } } |
Graphically:
|
(1) The algorithm will read S once: # disk I/Os = B(S) (2) # fragments Si read: B(S)/(M−1) times For each fragment Si, algorithm read R once # disk I/Os = B(S)/(M−1) × B(R) |
|
(Presented previously !!!)
(1) The algorithm will read S once: # disk I/Os = B(S) (2) # fragments Si read: B(S)/(M−1) times For each fragment Si, algorithm read R once # disk I/Os = B(S)/(M−1) × B(R) |
(Presented previously !!!)
(1) The algorithm will read R once: # disk I/Os = B(R) (2) # fragments Ri read: B(R)/(M−1) times For each fragment Ri, algorithm read S once # disk I/Os = B(R)/(M−1) × B(S) |