(non indexed) Total Scan Cost = enrollPage = 6,000
(Clustered indexed) Total Scan Cost
= innerNodeVisite + leafNodeNum
= (treeHeight - 1) + enrollPage / entryPerPage
= 2 + 6,000 / 100
= 2 + 60
= 62
(Unclustered indexed) Total Scan Cost
= innerNodeVisite + leafNodeNum + enrollPage
= 62 + 6000 = 6062
Operators
Filter Operator $\sigma$
Fetch table rows for predicate
Default: scan all pages, check each entry
Faster (not always):
Sorted: binary search for specific predicates
Indexed: right table, right key
Efficiency depends on query optimizer
Join Operator ⨝
one of the most expensive operations
Some are more generic and apply to any join predicate
Some are faster in specific situations
Some need less memory than others
Notations
LoadPage(P): Load page P
Pages(T): Pages from table T
Tuples(P): Tuples from page P
PageBlocks(T, b): Blocks of b pages from T
LoadPages(B): Load pages from block B
Index (Predicate): Entries satisfying predicate
Tuple (P, i): i-th tuple on page P
Page Nested Loop Join (first table = outer table)
1 2 3 4 5 6 7 8 9 10
⨝E.Sid = S.Sid
For ep in Pages(P1): LoadPage(ep) // Load each page in P1 For sp in Pages(P2): LoadPage(sp) // Load each page in P2 For et in Tuples(sp), st in Tuples(sp): // Compare every line if (et.Sid = st.Sid): Output(et⨝st)
Read inner table for each outer page
Cost = pageNum1 * load cost +
pageNum1 ** pageNum2 ** load cost +
pageNum1 ** pageNum2 ** evaluation cost
for (Load ALL pages from first table):
for (Load ALL pages from second table):
For all tuples in memory: check and add to result
Memory (1 + 1 + 1 = 3)
Store current page from outer table: 1
Store current page from inner table: 1
Need one buffer page to store output (before disk write): 1
For the intermediate result
Block Nested Loop Join (improved)
1 2 3 4 5 6 7 8 9
⨝E.Sid = S.Sid
For ep in PageBlocks(P1, b): LoadPage(ep) // each page in P1's block For sp in Pages(P2): LoadPage(sp) // load each page in P2 For et in Tuples(sp), st in Tuples(sp): if (et.Sid = st.Sid): Output(et⨝st)
Cost = pageNum1 * load cost +
blockNum1 ** pageNum2 ** load cost
Read inner table for each outer block
Block == multiple pages
Memory (B + 1 + 1 = B + 2)
Space to store blocks from outer relation: B
Space to store one page from inner relation: 1
Need one page to store output (before writing to disk): 1
Index Nested Loop Join
1 2 3 4 5 6
For ep in Pages(P1): LoadPage(ep) // Load each page in P1 For et in Tuples(ep): For <sp, i> in Index(et.Sid=st.Sid): // No need to load all due to index LoadPage(sp) Output(et ⨝ Tuple(sp, i))
Cost = pageNum1 * load cost +
indexEntryNum2 * load cost
Idea: have index on join column and equality predicate
Iterate over pages from non-indexed (outer) table
For each outer tuple, use index to find matching tuples
Memory (1 + 1 + 1 = 3)
• Store current page from outer table: 1 • Store current page from inner table: 1
output buffer (before disk write): 1
Equality Joins - Hash Join (Alternatives for Equality Joins)
Phase 1
Partition data by hash values in join columns (partition by even and odd value)
Read data + write partitioned data
cost = 2 * (pageNum1 + pageNum2)
Phase 2
Join each partition pair (same hash value)
Read data (NO Write)
cost = 1 * (pageNum1 + pageNum2)
cost = 3 * (pageNum1 + pageNum2)
Memory
Phase 1:
1 + # buckets
Phase 2:
2 + # Pages / # buckets
**Bucket num = $\sqrt(\text{smaller table Page num})$ **
If Lack Memory
Buffer pages size limits number of output buckets
Less buckets -> more data in each bucket
Prevents loading one bucket entirely in Phase 2
Perform multiple passes over data in phase 1
Partition buckets into sub-buckets
Iterate until data per bucket fits into main memory
Equality Joins - Sort-Merge Join (SMJ) (Sub-optimal in memory)
Phase 1 (Sort)
Sort the join column (single entries) in joined tables
inefficient to random data access
Access pages of entries instead to fit into memory
Phase 2 (Merge)
Load first page of both sorted tables into memory
Find matching tuples and add to join result output
Load next page for table with smallest last entry
Keep doing until no pages left for one table
Algorithm
B: buffer pages available
run: A sorted sequence of data = a chunk of data in memory
load & sort & write to disk (runs = pageNum / bufferSize)
Load: chunks of B pages into the buffer
sort: each chunk
write: sorted data to hard disk
merge B-1 sorted runs into 1 in one step: produce larger runs & less number of runs
Load first page of each sorted run into B-1 pages
Copy minimum entry in input buffers to output buffer
If output buffer full, write to disk and clear
Erase minimum entry from input buffer
If input buffer becomes empty, load next page
one sorted run left
Cost
Two input tables with M and N pages, B buffer pages
Phase 1
2 ** M ** ($1 + Ceil(log**{B-1}(N/B))$) for sorting table 1
2 ** N ** $(1 + Ceil(log**{B-1}(N/B))$) for sorting table 2
Multiple sorting passes, we read and write data once in each
Cost per pass is 2 * (number of pages)
steps to make with B buffer pages:
First step: runs of length B
Second step: runs of length (B-1) * B
Third step: runs of length (B-1) ** (B-1) ** B …
Phase 2
M+N (we don’t count cost for writing output!)
After sotting, all duplicate entries on same page
Duplicate entry: same value in join column
Each input page is only read once
Cost is proportional to number of input pages
Memory
Phase 1: use all buffer pages
More buffer == less merging passes
Phase 2: exploit 3 buffer pages
3 for 1st input & 2nd input & output
Refined Sorted-Merge Join (Refined SMJ)
Idea: save steps by merging more than 2 sorted tables (No sorting tables completely in phase 1)
Assume B buffer pages, tables with N and M pages
Phase 1:
Only sort data chunks that fit into memory
load chunks of B pages & sort & write back
Phase 2: merge ALL sorted tables
Join all sorted chunks together (one step)
merge B-1 sorted chunks together
Cost:
2 * (M+N) (Phase 1) + 1 * (M+N) (Phase 2)
Memory
First phase:
(N+M)/B sorted runs
Merge in one step:
B ≥ 1+(N+M)/B
Rule of thumb:
if N>M: need B ≥ 2 * √(N)
Projection $\pi$
SELECT without DISTINCT
Calculate SELECT items, drop other columns
If DISTINCT
Filter out duplicates by hash function / sorting / index
Projection & Duplicate Elimination via Hashing
Phase 1: partition data into hash buckets
Scan input, calculate projection, partition by hash function
Data partitions: write to hard disk (data size exceeds memory)
cost: read input (1 ** num of pages) + write partitioned pages (1 ** num of pages)
Phase 2: eliminate duplicates for each partition
Read one partition into memory and eliminate duplicates
Can use second hash function to detect duplicates
cost: read partition pages (1 ** num of pages) + write duplicated pages (1 ** num of pages)
Constraints on memory similar as for hash join
Count hash buckets for Phase 1, bucket size for Phase 2
Bucket size may not fit in memory
Max Cost = 3 * Number of Pages
Projection & Duplicate Elimination via Sorting
Max Cost: external sorting cost
Idea: sorting rows to find duplicates
Variant of external sort algorithm
Apply projection during first pass over data
Eliminate in-memory duplicates during all steps
Now duplicate-free and sorted
Reduce number of passes with more main memory
Projection & Duplicate Elimination via Index
Max Cost: reading index data
Retrieve relevant data by index
Assume index key includes projection columns (可以通过 index 找到 projection 里面的 attribute)
Saves cost considering index smaller than data
Even better: tree index with projections as key prefix
Duplicates retrieved consecutively, easy to eliminate