Knowledge / Computer Science and Engineering / Query processing and optimisation

Query processing and optimisation

Computer Science and Engineering (B.E./B.Tech) · Databases · free study notes for exams, placements and interviews

In short

Query processing is the sequence of steps a DBMS follows to turn a declarative SQL statement into an executable plan and run it; query optimisation is the step that chooses, among many equivalent plans, the one with the least estimated cost. Because SQL says *what* is wanted and not *how*, the same query can differ in run time by factors of thousands depending on join order, join algorithm and access path. It is examined in every university DBMS paper (cost formulas for joins, equivalence rules, external sorting) and in GATE CS/DA through relational algebra equivalence and cost estimation. On the job it is the core skill behind reading EXPLAIN plans at Flipkart, Zoho, Infosys, TCS, Wipro, Freshworks, NPCI/UPI and UIDAI-scale systems, where a missing index or a bad join order shows up directly as breached SLAs.

Explained

The three stages of query processing

  1. Parsing and translation — the parser checks syntax, the semantic analyser validates table and column names, types and privileges against the system catalog (data dictionary), expands views and synonyms, and produces an internal tree.
  2. Optimisation — the tree is converted to relational algebra, rewritten using equivalence rules, annotated with algorithms and access paths to form candidate query evaluation plans (QEPs), each costed; the cheapest is selected.
  3. Evaluation (execution) — the execution engine runs the chosen plan through the operator tree and returns the result.
  4. An annotated expression tree = relational algebra operator + chosen algorithm + chosen access path; this is what EXPLAIN prints.
  5. Canonical (initial) form: the naive translation — Cartesian products of all FROM tables, then one big selection from WHERE, then projection. Always correct, almost always disastrous; optimisation's job is to transform it.
  6. Query graph: nodes are relations, edges are join predicates; used to reason about join order and to spot Cartesian products.

Relational algebra equivalences and heuristic optimisation

Equivalence rules (both sides give the same multiset for every instance):

Cost model and statistics

Implementing selection, projection, sorting and aggregation

Selection access paths (the classic A1–A7 list):

Join algorithms and their costs

Cost-based plan enumeration (System R and after)

Evaluation: materialisation, pipelining and reading plans

Key points

Formulas and examples

b_r = ⌈n_r / f_r⌉ ; f_r = ⌊block size / l_r⌋ (n_r = tuples, b_r = blocks, l_r = bytes per tuple)
Equality selection size: σ_{A=a}(r) ≈ n_r / V(A, r) ; if A is a key, ≈ 1
Range selection size: σ_{A>v}(r) ≈ n_r · (max(A) − v) / (max(A) − min(A)) ; 0 if v ≥ max, n_r if v ≤ min
Conjunction: n_r · (s₁·s₂·…·sₙ) ; Disjunction: n_r · [1 − (1−s₁)(1−s₂)…(1−sₙ)] ; Negation: n_r − |σ_θ(r)| ; sᵢ = selectivity = |σ_{θi}(r)| / n_r
Join size (common attribute A): n_r·n_s / max(V(A,r), V(A,s)) ; Cartesian product if no common attribute: n_r·n_s
External sort: initial runs = ⌈b_r/M⌉ ; passes = 1 + ⌈log_{M−1}(⌈b_r/M⌉)⌉ ; block transfers = 2·b_r·passes (subtract b_r if the final output is pipelined)
Nested-loop join = b_r + n_r·b_s ; Block nested-loop = b_r + ⌈b_r/(M−2)⌉·b_s ; Index nested-loop = b_r + n_r·c, c ≈ h+1
Sort-merge join = sort(r) + sort(s) + b_r + b_s ; Hash join = 3(b_r + b_s) (no recursive partitioning, needs M > √b_build)
Plan space: left-deep orders = n! ; all tree shapes = (2(n−1))!/(n−1)! ; System R DP time O(3ⁿ), space O(2ⁿ)

Example 1 — selectivity and result size. employee: n = 50,000; V(dept) = 25; salary from ₹10,000 to ₹2,00,000 per month.

Example 2 — index scan versus full scan (the crossover). Table: n = 100,000 tuples, f = 20 → b = 5,000 blocks. Predicate on a non-key with V = 200 → 500 matching tuples. Unclustered secondary B⁺-tree of height 3.

Example 3 — join algorithms compared. r = student: n_r = 5,000, b_r = 100 blocks; s = takes: n_s = 10,000, b_s = 400 blocks; M = 12 buffer blocks; B⁺-tree on takes(ID) of height 4.

AlgorithmWorkingBlock transfers
Nested-loop (r outer, tuple level)100 + 5,000 × 4002,000,100
Block nested-loop (r outer, 3 buffers)100 + 100 × 40040,100
Block nested-loop (r outer, M = 12)100 + ⌈100/10⌉ × 4004,100
Sort-mergesort r 400 + sort s 2,400 + 5003,300
Hash join (r = build)3 × (100 + 400)1,500

Example 4 — pushing a selection, and why it flips the plan. Add WHERE student.dept = 'CSE', V(dept, student) = 20, f_student = 50 tuples/block. ID is a key of student, V(ID, takes) = 5,000.

Example 5 — reading an EXPLAIN plan.

EXPLAIN (ANALYZE, BUFFERS)
SELECT e.emp_id, e.name, SUM(p.amount)
FROM   employee e JOIN payroll p ON p.emp_id = e.emp_id
WHERE  e.dept = 'Sales' AND p.pay_month >= '2026-04-01'
GROUP BY e.emp_id, e.name;
HashAggregate  (rows=1021) (actual rows=1018 loops=1)
  -> Hash Join  (cost=..  rows=1053) (actual rows=12204 loops=1)
       Hash Cond: (p.emp_id = e.emp_id)
       -> Seq Scan on payroll p  (rows=26316) (actual rows=61020)
            Filter: (pay_month >= '2026-04-01')
       -> Hash  (rows=2000) (actual rows=2000)
            -> Index Scan using emp_dept_ix on employee e (rows=2000)

Where it is used

Interview questions

Common mistakes

Related topics

SQL queries and joins · Transactions, ACID and indexing · Advanced SQL: subqueries, CTEs and window functions · ER model and normalisation · Database design case studies · NoSQL databases

Open in the Knowledge reader →Find jobs →