Computer Science / Relational Query Optimization
FREE TO EXPLORE
LABORATORY 25 · COMPUTER SCIENCE

Relational Query Optimization & Execution: Relational Algebra Equivalence, Cost-Based Join Optimization (Nested Loop vs Hash Join vs Sort-Merge), and Index Scan Selectivity

Measure the empirical tuple comparison counts and physical I/O costs of Relational Join Operators (Nested Loop Join, Block Nested Loop Join, Sort-Merge Join, and Hash Join) across relation cardinalities N from 1,000 to 7,000 tuples, evaluate relational algebra equivalence transformations, analyze index scan selectivity tipping points, and extract the fundamental hash join linear scaling multiplier k_join using ordinary least-squares regression. Explore interactive search algorithms, compare operation counts and analyse complexity scaling.

COMPUTE · BENCHMARK · ANALYSE

Your virtual algorithm laboratory.

HASH JOIN TUPLE COMPARISONS T_HASH—
EXECUTION STATUS

Ready to execute cardinality benchmark.

4000 tuples
Uniformly distributed integer join key space with primary key domain [1 .. 2N] and foreign key references.

Adjust cardinality n, then execute benchmark.

Operation counts are generated deterministically by the exact algorithmic execution model. Modern hardware benchmarks additionally reflect cache line prefetching and branch misprediction penalties.

Algorithmic assumptions and limits

The simulated benchmark models an in-memory hash join with uniform key distributions and negligible bucket collision chaining, resulting in deterministic operation scaling T(N) = 2N. In physical enterprise database engines (PostgreSQL, MySQL InnoDB, Oracle, Microsoft SQL Server), execution latency is heavily modulated by: (1) external memory Grace hash partitioning and multi-pass disk I/O when relation size exceeds buffer pool capacity M; (2) data skew and duplicate join keys ('heavy hitters') creating unbalanced hash chains; (3) NUMA memory bus node remote access penalties on multi-socket database servers; (4) parallel query execution thread synchronization and exchange operator (Tuple Mover / Gather) serialization overhead; and (5) cardinality estimation errors propagating exponentially through multi-join query trees. In an in-memory equi-join between two relations R and S of identical cardinality |R| = |S| = N, the classical Hash Join algorithm operates in two sequential phases: (1) Build Phase: The optimizer designates relation R as the build input. For each of the N tuples in R, the engine evaluates the hash function on the join key h(t_R.k) and inserts the tuple into the corresponding hash bucket, performing exactly N insertion operations. (2) Probe Phase: The engine scans relation S as the probe input. For each of the N tuples in S, it computes the hash value h(t_S.k), accesses the hash bucket, and evaluates the join predicate against matching candidate keys. Under uniform hash distribution and unique primary-foreign key relationships, each probe executes exactly 1 tuple comparison, totaling N probe comparisons. The total operation count is strictly T(N) = N (build insertions) + N (probe comparisons) = 2.0000 · N operations. Ordinary least-squares linear regression against tuple cardinality N yields an empirical scaling multiplier of k_join = 2.0000 comparisons/tuple with baseline intercept T_0 = 0.0000 operations and correlation coefficient R² = 1.00000. In contrast, Nested Loop Join scales quadratically as C_nlj(N) = N², Block Nested Loop Join incurs B(R) + ⌈B(R)/(B-2)⌉ · B(S) disk block transfers, and Sort-Merge Join incurs 2 B(R) log_{B-1}(B(R)/B) + 2 B(S) log_{B-1}(B(S)/B) + B(R) + B(S) block I/Os.

Computational tools & environment.

Relational Query Optimization Engine & AST Parser

Parses SQL declarative queries into relational algebra Abstract Syntax Trees (AST), applying rewrite transformations and generating candidate physical operator DAGs.

System R Cost-Based Optimizer & DP Enumerator

Implements Selinger dynamic programming algorithm searching left-deep join orderings, evaluating CPU and I/O cost formulas, and preserving interesting sort orders.

In-Memory Dual-Phase Hash Join Operator

Executes partition hashing and bucket chaining across build and probe relations, recording atomic hash computations, bucket insertions, and key comparison operations.

Block-Buffer Memory Management Unit (Buffer Pool)

Allocates B = 64 memory frames (each 4KB) with LRU replacement policy, tracking disk page block I/Os, cache hits, and dirty page writeback counts.

B+ Tree Clustered & Unclustered Secondary Index Unit

Maintains tree indexing over relation attributes, providing logarithmic key lookups and simulating index scan selectivity tipping points against sequential full scans.

Catalog Statistics & Histogram Profiler

Maintains relation metadata including cardinality |R|, page count B(R), distinct attribute values V(A, R), and equi-depth histograms for selectivity estimation.

FOLLOW THE METHOD

A reason behind every step.

Measure the empirical tuple comparison counts and physical I/O costs of Relational Join Operators (Nested Loop Join, Block Nested Loop Join, Sort-Merge Join, and Hash Join) across relation cardinalities N from 1,000 to 7,000 tuples, evaluate relational algebra equivalence transformations, analyze index scan selectivity tipping points, and extract the fundamental hash join linear scaling multiplier k_join using ordinary least-squares regression. Suggested independent settings: 1000, 2000, 3000, 4000, 5000, 6000, 7000 tuples.

01

Catalog Statistics Calibration and Buffer Pool Allocation

Configure the database engine with buffer pool size B = 64 pages (4KB page size). Populate the system catalog with metadata for relations R and S across benchmark cardinalities N in [1000, 2000, 3000, 4000, 5000, 6000, 7000] tuples, setting tuple size to 80 bytes (50 tuples per 4KB page, B(R) = B(S) = N/50 pages).

02

Logical Query Tree Construction and Heuristic Rewriting

Parse the declarative join query into a canonical relational algebra tree: π_{R.name, S.dept} (σ_{R.age > 30 ∧ S.budget > 50000} (R ⋈_{R.dept_id = S.id} S)). Apply heuristic optimization rules: push selections σ below joins to filter base relations early, and push projections π to prune unused columns before buffering.

03

Cost Model Estimation Across Join Paradigms

Compute theoretical cost estimates for candidate physical join operators using catalog statistics: evaluate Nested Loop Join (C_nlj = N² comparisons), Block Nested Loop Join (I/O = B(R) + ⌈B(R)/(B-2)⌉ · B(S)), Sort-Merge Join (I/O = 3(B(R) + B(S))), and Hash Join (I/O = 3(B(R) + B(S)) external, or in-memory T(N) = 2N operations).

04

In-Memory Hash Join Build Phase Execution

Initiate execution of the in-memory Hash Join. Designate relation R as the inner build relation. Allocate a hash table with 2N slots. For each tuple t_R in R, evaluate hash function h(t_R.dept_id), insert the tuple into the corresponding bucket, and record N build operations.

05

In-Memory Hash Join Probe Phase Execution

Scan outer relation S as the probe input. For each tuple t_S in S, evaluate h(t_S.id) to index into the hash table bucket. Traverse the bucket's linked chain and evaluate key equality (t_R.dept_id == t_S.id). Under uniform distribution and unique keys, execute exactly 1 key comparison per probe tuple, recording N probe comparisons.

06

Notebook Recording and Linear Scaling Validation

Record total tuple comparison operations T_hash = 2N into the notebook. Repeat across all relation cardinalities N in [1000, 2000, 3000, 4000, 5000, 6000, 7000]. Plot T against N and perform ordinary least-squares regression to verify slope k_join = 2.0000 comparisons/tuple, intercept T_0 = 0.0000, and R² = 1.00000.

YOUR NOTEBOOK · 0 OBSERVATIONS

Turn measurements into asymptotic insight.

See a complete example report ↗

Points are your recorded benchmark observations. The regression line validates Relational Query Optimization complexity scaling.

LINEAR ASYMPTOTIC FIT · y = mx + b
T = k_join · N + T_0; k_join = m
#Relation cardinality N (tuples) (tuples)Hash join tuple comparisons T_hash (comparisons)Relation tuple space N (tuples)Hash join tuple comparisons T (operations)Remove

No readings yet. Execute a cardinality benchmark and record it.

Calculate it yourself.

CHECK YOUR UNDERSTANDING

Explain what the operation counts mean.

In an in-memory Hash Join between relation R and relation S, each containing N tuples with unique join keys, what is the exact number of tuple operations performed across the Build and Probe phases?

What is the primary motivation for the System R (Selinger) optimizer restricting its search space to Left-Deep Join Trees?

Why might a cost-based query optimizer intentionally choose a Full Table Scan over an Unclustered Secondary B+ Tree Index for a range query?

Under the Uniform Distribution Assumption, if attribute age in relation Employee (containing 50,000 tuples) has 50 distinct values (V(age, Employee) = 50), what is the estimated cardinality of σ_{age = 30}(Employee)?