Study Vault Search notes, aliases and full text
Graph
TopicDBISAI-written · not yet proofread

SQL and Query Planning

How relational data is stored and queried with SQL, how a query is translated into table operations, and how the cheapest query plan is chosen (joins, indexes, join ordering), plus transactions.

Concepts#

  1. Relational Modeltables (C,D,R)(C, D, R) as multisets of rows, primary and foreign keys start here
  2. SQL Query Structureclauses SELECT … FROM … WHERE … GROUP BY … HAVING … ORDER BY … LIMIT and their evaluation order
  3. Cartesian Productall row combinations; semantics of FROM, columns add up and rows multiply
  4. Relational Algebraprojection, selection, product and their cost/size estimates; query as sequence/tree of operations
  5. Join $T_1 \bowtie T_2$equi-join as a product + selection computed without the product; outer and natural joins, hash join
  6. Merge Joinjoin of sorted join columns by the Zipper algorithm
  7. group-by(T, cols, agg)group-by with aggregation functions and HAVING
  8. OrderingORDER BY, LIMIT, OFFSET
  9. Subquerya SELECT query used in place of a table
  10. Query Plana sequence/expression/tree of operations with its estimated total cost
  11. B+ Treeindex with O(log⁡n)O(\log n) lookup, sorted leaves; basis of index-based joins
  12. Query Optimizationjoin graph and cost∗(S)\text{cost}^*(S) by dynamic programming over subsets
  13. ACIDtransaction guarantees (mentioned only, not exam-relevant)

How it fits together#

From a query to a result. A query SELECT … FROM … WHERE … is defined by a chain of operations on tables: the FROM tables are combined by the Cartesian Product, the WHERE expression selects rows (σ\sigma), the SELECT list projects columns (Π\Pi). GROUP BY/HAVING, ORDER BY/LIMIT and subqueries extend this chain; a subquery works because every operation takes tables and returns a table (Relational Model > Closure). This definition says what is computed, not how: the RDBMS is free to compute any equivalent plan.

From definition to efficient plan.

StepProblemRemedyConcept
1Product materialises n1n2(k1+k2)n_1 n_2 (k_1 + k_2) valuespush σ\sigma and Π\Pi below the product; combine small tables firstRelational Algebra
2Product + equality selection is still too largesingle-column equi-join, never materialising the productJoin
3Join needs a fast way to find matcheshash join (hash map), or merge join on sorted columnsJoin, Merge Join
4Sorted columns / fast lookups are neededindex B+ tree: lookup O(log⁡n)O(\log n), leaves in sorted orderB+ Tree
5Many tables: which join order?join graph, cost∗(S)\text{cost}^*(S) by dynamic programmingQuery Optimization

Cost models by lecture. All of them are sums over the operations of a Query Plan, with sizes propagated from the leaves:

LectureOperationcostrowscols
VL04Π\Pink′n k'nnk′k'
VL04σ\sigmankn kn/2n/2kk
VL04×\timesn1n2(k1+k2)n_1 n_2 (k_1 + k_2)n1n2n_1 n_2k1+k2k_1 + k_2
VL05hash/merge joinn1+n2+min⁡(n1,n2)kn_1 + n_2 + \min(n_1, n_2) kmin⁡(n1,n2)\min(n_1, n_2)kk
VL05group-bynkn kn/2n/2kk
VL06join (total cost, size only)cost(A)+cost(B)+size\text{cost}(A) + \text{cost}(B) + \text{size}min⁡(size(A),size(B))\min(\text{size}(A), \text{size}(B))–

Which one to use depends on the task: the exam gives the VL04 estimates (select/project/product) for plan comparison; the VL06 model with cost∗\text{cost}^* is for join ordering of many tables.

Joins and indexes.

Hash joinMerge JoinIndex lookup (SQLite3)
Needsnothingboth join columns sortedB+ Tree on one join column (temporary one if none)
TimeCIn1+CLn2+CCnkC_I n_1 + C_L n_2 + C_C n kCM(n1+n2+n)+CCnkC_M (n_1 + n_2 + n) + C_C n kn1n_1 lookups of O(log⁡n2)O(\log n_2)
Notesimple defaultfaster (CM≪CIC_M \ll C_I); fed by B+ tree leavesan index on both columns does not help further

When SQL needs more than one clause. “Per group, a value” → Grouping; “per group, the row with the extreme value” (argmax) cannot be done by GROUP BY alone and needs a Subquery joined back to the table. WHERE filters rows before grouping, HAVING filters groups after aggregation. NATURAL JOIN joins on all equally named columns, so tracing a natural join with a subquery means checking which names the two tables share.

Related. Basic SPARQL queries translate mechanically into the joins above (SPARQL and Knowledge Graphs).

Key Formulas#

  • cost(T1×T2)∼n1n2(k1+k2)\text{cost}(T_1 \times T_2) \sim n_1 n_2 (k_1 + k_2), cost(σ)∼nk\text{cost}(\sigma) \sim nk, cost(Π)∼nk′\text{cost}(\Pi) \sim nk' (Relational Algebra)
  • #cols(T1×⋯×Tk)=∑i#cols(Ti)\#\text{cols}(T_1 \times \dots \times T_k) = \sum_i \#\text{cols}(T_i), #rows=∏i#rows(Ti)\#\text{rows} = \prod_i \#\text{rows}(T_i) (Cartesian Product)
  • cost(A⋈B)=cost(A)+cost(B)+min⁡{size(A),size(B)}\text{cost}(A \bowtie B) = \text{cost}(A) + \text{cost}(B) + \min\{\text{size}(A), \text{size}(B)\} (Query Plan)
  • cost∗(S)=min⁡S1∪S2=S{cost∗(S1)+cost∗(S2)+size(S1⋈S2)}\text{cost}^*(S) = \min_{S_1 \cup S_2 = S}\{\text{cost}^*(S_1) + \text{cost}^*(S_2) + \text{size}(S_1 \bowtie S_2)\}, cost∗({T})=0\text{cost}^*(\{T\}) = 0 (Query Optimization)
  • B+ tree lookup: depth ≤⌈log⁡dn⌉\le \lceil \log_d n \rceil, time O(log⁡n)O(\log n) (B+ Tree)

Exercises & Exam Questions#

SuccessSolution Q1

(a)

SELECT title FROM movies
WHERE release_year > 1900 AND release_year <= 2000;

(b)

SELECT movies.title, SUM(streaming.views) AS total_views
FROM movies, streaming
WHERE movies.id = streaming.movie_id
  AND streaming.platform IN ("Netflix", "Amazon Prime")
GROUP BY movies.id
ORDER BY total_views DESC
LIMIT 10;

(c)

SELECT movies.title, GROUP_CONCAT(persons.name, ', ')
FROM movies, actors, persons
WHERE movies.id = actors.movie_id
  AND actors.person_id = persons.id
GROUP BY movies.id
HAVING COUNT(actors.person_id) >= 10;
SuccessSolution Q2

Plan 1: 40+40+300+300=68040 + 40 + 300 + 300 = 680

  • select(A): 10⋅4=4010 \cdot 4 = 40 (5 rows out)
  • select(B): 20⋅2=4020 \cdot 2 = 40 (10 rows out)
  • cross product: 5⋅10⋅6=3005 \cdot 10 \cdot 6 = 300 (50 rows out)
  • project: 50⋅6=30050 \cdot 6 = 300

Plan 2: 1200+1200+600+300=33001200 + 1200 + 600 + 300 = 3300

  • cross product: 10⋅20⋅6=120010 \cdot 20 \cdot 6 = 1200 (200 rows out)
  • select: 200⋅6=1200200 \cdot 6 = 1200 (100 rows out)
  • select: 100⋅6=600100 \cdot 6 = 600 (50 rows out)
  • project: 50⋅6=30050 \cdot 6 = 300

Plan 2 can be cheaper if one table is empty (0 rows): then cross product costs 0 in Plan 2, but Plan 1 still pays for the selection on the non-empty table.

SuccessSolution Q3
  1. Subquery computes max score per year: (2021, 8.3), (2022, 8.2), (2023, 8.4)
  2. NATURAL JOIN matches on both year AND score – only movies whose score equals the max for their year survive
  3. Result after ORDER BY score DESC:
    • (2023, Oppenheimer, 8.4), (2021, Spider-Man, 8.3), (2022, Top Gun, 8.2)

Natural language: For each year, the movie with the highest score, ordered by score descending.

SuccessSolution Q4

Computes each employee’s name together with the name of their supervisor (self-join on supervisor = id); RR is 100×2100 \times 2.

Original: 100⋅100⋅6+10 000⋅6+100⋅2=60 000+60 000+200=120 200100 \cdot 100 \cdot 6 + 10\,000 \cdot 6 + 100 \cdot 2 = 60\,000 + 60\,000 + 200 = 120\,200.

Better: project both copies before the product: E′=Π(2,3)(E)E' = \Pi_{(2,3)}(E), E′′=Π(1,2)(E)E'' = \Pi_{(1,2)}(E), C=E′×E′′C = E' \times E'', S=σrow[2]=row[3](C)S = \sigma_{\text{row}[2] = \text{row}[3]}(C), R=Π(1,4)(S)R = \Pi_{(1,4)}(S). Cost: 200+200+100⋅100⋅4+10 000⋅4+200=80 600200 + 200 + 100 \cdot 100 \cdot 4 + 10\,000 \cdot 4 + 200 = 80\,600.

SuccessSolution Q5
SELECT person
FROM founded_by NATURAL JOIN based_in NATURAL JOIN born_in;

The first natural join is on company, giving (company, person, city); joining born_in is on person and city. Equivalent: explicit JOIN … ON f.company = b.company and JOIN born_in n ON f.person = n.person AND b.city = n.city, or three tables in FROM with the three equalities in WHERE.

SuccessSolution Q6

(2) A subquery with GROUP BY e_id, title HAVING COUNT(*) > 1 yields the qualifying pairs, joined with employees:

SELECT DISTINCT e.name
FROM employees AS e, (
  SELECT e_id, title FROM positions
  GROUP BY e_id, title HAVING COUNT(*) > 1
) AS p
WHERE e.id = p.e_id;

(3) A subquery computes MAX(start_date) per employee and is joined back on employee and date:

SELECT e.name, p.title
FROM employees AS e, positions AS p, (
  SELECT e_id, MAX(start_date) AS latest_date
  FROM positions GROUP BY e_id
) AS pmax
WHERE e.id = p.e_id AND p.e_id = pmax.e_id
  AND p.start_date = pmax.latest_date;

Exam occurrences#

SemesterTaskPointsSubtopics
DBIS Exam WS1314 (not published)T620SPARQL-to-SQL translation, efficient query processing with indexes
DBIS Exam WS1516 (not published)T620SQL for knowledge base queries, inverted index size formula
DBIS Exam WS1617 (not published)T620SQL for knowledge base, maximum entropy proof
DBIS Exam WS2324 (not published)T220SQL queries on movie schema, query plan cost comparison
DBIS Exam WS2324 (not published)T320SQL/SPARQL translation, NATURAL JOIN step-by-step
DBIS Exam WS2324-2 (not published)T220SQL queries with subqueries on employees schema, self-join query plan cost
DBIS Exam WS2324-2 (not published)T320SPARQL-to-SQL, subquery with GROUP BY and AVG

Lectures#

  • DBIS_VL03 — relational model, SQLite3, database design with keys, SELECT … FROM … WHERE … via the cross-product
  • DBIS_VL04 — projection, selection, Cartesian product, query planning and cost estimates
  • DBIS_VL05 — join (hash, merge, outer, natural), group-by and HAVING, ORDER BY, LIMIT/OFFSET, subqueries
  • DBIS_VL06 — index B+ tree, optimal query plan by dynamic programming, ACID
  • DBIS_VL13 — exam example task on query plan costs

Search

Type In
↑ ↓ move ↵ open ⇥ next section Ctrl↵ results page Prefix # to search text only