💡 The query plan successfully produces the desired ranked output.
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
# STEP 1: Create sales table
cursor.execute('''CREATE TABLE sales (product_id TEXT, category TEXT, sales_amount REAL, sale_date TEXT)''')
sales_data = [
('P1', 'Electronics', 100, '2023-01-01'), # STEP 2-5: Insert rows
('P2', 'Electronics', 150, '2023-01-01'),
('P3', 'Books', 200, '2023-01-01'),
('P4', 'Books', 50, '2023-01-03')
]
cursor.executemany('INSERT INTO sales VALUES (?, ?, ?, ?)', sales_data)
conn.commit()
# STEP 6-10: Execute query with aggregation and window function
query = '''
SELECT category, product_id, total_sales,
RANK() OVER (PARTITION BY category ORDER BY total_sales DESC) AS rank
FROM (
SELECT category, product_id, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY category, product_id
) sub
ORDER BY category, rank
'''
cursor.execute(query) # STEP 11-17: Execute and fetch results
results = cursor.fetchall()
print('Ranking products within each category:')
for row in results:
print(row)
conn.close()
📊
Aggregate Functions - GROUP BY, HAVING, Window Functions - Watch the Algorithm Execute, Step by Step
Watching the query plan step-by-step reveals how SQL engines optimize and execute complex queries involving grouping, filtering, and window functions, which is hard to grasp from code alone.
Step 1/17
·Active fill★Answer cell
Sequential scan operator is reading rows from sales table.
SeqScansalesrows≈4cost=10
Aggregaterows≈4
Windowrows≈4
Sortrows≈4
Rows processed: 0
No index available, so full table scan is necessary.
Sequential scan reads first row: P1, Electronics, 100.
SeqScansalesrows≈4cost=10
Aggregaterows≈4
Windowrows≈4
Sortrows≈4
Rows processed: 1
Row-by-row reading feeds aggregation.
Sequential scan reads second row: P2, Electronics, 150.
Aggregate operator groups rows by category and product_id, summing sales_amount.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4
Sortrows≈4
Rows processed: 0
Aggregation uses hash or sort-based grouping.
Aggregate sums sales_amount for Electronics, P1: 100.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4
Sortrows≈4
Rows processed: 1
Aggregation output row created.
Aggregate sums sales_amount for Electronics, P2: 150.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4
Sortrows≈4
Rows processed: 2
Aggregation output row created.
Aggregate sums sales_amount for Books, P3: 200.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4
Sortrows≈4
Rows processed: 3
Aggregation output row created.
Aggregate sums sales_amount for Books, P4: 50. Aggregation complete.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4
Rows processed: 4
Aggregation output ready for window function.
Window operator starts ranking products within each category by total_sales descending.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4
Rows processed: 0
Window function computes rank without grouping.
Window function assigns rank 1 to P3 in Books category (200 sales).
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4
Rows processed: 1
Ranking uses partition and order.
Window function assigns rank 2 to P4 in Books category (50 sales).
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4
Rows processed: 2
Ranking continues within partition.
Window function assigns rank 1 to P2 in Electronics category (150 sales).
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4
Rows processed: 3
Ranking resets for new partition.
Window function assigns rank 2 to P1 in Electronics category (100 sales).
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4cost=5
Rows processed: 4
Ranking complete for all partitions.
Sort operator orders rows by category and rank.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4cost=5
Rows processed: 0
Sorting prepares final output order.
Final sorted rows output to user.
SeqScansalesrows≈4cost=10
Aggregaterows≈4cost=20
Windowrows≈4cost=30
Sortrows≈4cost=5
Rows processed: 4
Query execution complete.
Key Takeaways
✓ The query plan shows how raw data is first scanned, then grouped, ranked, and finally sorted for output.
This stepwise flow is hard to see from code but clear in the visualization.
✓ Window functions like RANK() compute rankings within partitions without collapsing rows, preserving detail.
Understanding window functions is easier when seeing how they operate after aggregation.
✓ Sorting at the end ensures the final output is logically ordered by category and rank for user consumption.
Sorting is a separate step that organizes results after all computations.
Practice
(1/5)
1. Trace the sequence of events when a transaction commits in a database that guarantees Durability. What happens immediately after the commit command?
easy
A. The transaction's changes are written to volatile memory and then acknowledged
B. The transaction's changes are visible to other transactions before being saved
C. The transaction's changes are flushed to stable storage before acknowledgment
D. The transaction's changes are rolled back if a system failure occurs immediately after commit
Solution
Step 1: Recall Durability definition
Durability means once a transaction commits, its changes survive system failures.
Step 2: What ensures durability?
Changes must be flushed to stable storage (disk) before acknowledging commit.
Step 3: Analyze options
A is incorrect because volatile memory is not durable. B is about visibility, not durability. D contradicts durability.
Final Answer:
Option C -> Option C
Quick Check:
Durability requires stable storage flush before commit acknowledgment.
Hint: Durability = flush to disk before commit confirmation
Common Mistakes:
Assuming volatile memory is enough for durability
Confusing visibility with durability
2. In which scenario is MVCC most beneficial compared to traditional locking mechanisms in a database system?
easy
A. When strict serializability is required and no stale reads are allowed
B. When transactions are short-lived and mostly write-heavy with minimal reads
C. When many concurrent transactions perform mostly read operations with occasional writes
D. When the database workload consists primarily of batch updates with no concurrent reads
Solution
Step 1: Understand MVCC's strength in concurrency
MVCC allows readers to access snapshot versions without blocking writers, making it ideal for workloads with many reads and fewer writes.
Step 2: Analyze write-heavy workloads
Write-heavy workloads with minimal reads benefit less from MVCC since version maintenance overhead can be costly.
Step 3: Analyze batch updates without concurrent reads
Batch updates without concurrent reads do not leverage MVCC's snapshot isolation benefits.
MVCC provides snapshot isolation, which may allow some anomalies; strict serializability requires stronger mechanisms.
Final Answer:
Option C -> Option C
Quick Check:
MVCC shines in read-heavy concurrent environments [OK]
Hint: MVCC excels when many reads coexist with some writes
Common Mistakes:
Assuming MVCC is best for write-heavy workloads
Confusing snapshot isolation with strict serializability
Believing MVCC is unnecessary without concurrent reads
3. Trace the sequence of lock acquisitions and releases when two transactions T1 and T2 both request shared locks on the same data item, followed by T1 requesting an exclusive lock on that item. What happens step-by-step?
easy
A. T1 acquires exclusive lock first; T2 waits for T1 to release before acquiring shared lock
B. T1 and T2 acquire shared locks simultaneously; T1 upgrades to exclusive lock immediately without waiting
C. T1 acquires shared lock; T2 waits until T1 releases its lock before acquiring shared lock
D. T1 and T2 acquire shared locks; T1 must wait to upgrade to exclusive lock until T2 releases its shared lock
Solution
Step 1: Both transactions request shared locks
Shared locks are compatible, so T1 and T2 both acquire shared locks simultaneously.
Step 2: T1 requests exclusive lock (lock upgrade)
Exclusive lock is incompatible with shared locks held by others, so T1 must wait until T2 releases its shared lock.
T1 cannot upgrade immediately; it must wait for T2 to release.
Final Answer:
Option D -> Option D
Quick Check:
Lock compatibility rules prevent immediate exclusive lock upgrade when others hold shared locks.
Hint: Exclusive lock upgrade waits for all shared locks to release [OK]
Common Mistakes:
Assuming lock upgrade is immediate despite other shared locks
Believing shared locks are exclusive
Ignoring lock compatibility rules
4. What is a key trade-off or limitation of MVCC in terms of storage and performance?
medium
A. MVCC requires maintaining multiple versions, increasing storage and cleanup complexity
B. MVCC guarantees serializable isolation without any anomalies
C. MVCC eliminates all locking overhead, resulting in zero contention
D. MVCC reduces write amplification by avoiding version creation
Solution
Step 1: Understand MVCC version management
MVCC stores multiple versions of rows to provide snapshot isolation, which increases storage usage and requires vacuuming or cleanup.
Step 2: Analyze locking overhead
MVCC reduces locking but does not eliminate all contention, especially for writes.
Step 3: Analyze isolation guarantees
MVCC typically provides snapshot isolation, which can allow anomalies; serializability requires additional mechanisms.
Step 4: Analyze write amplification
MVCC increases write amplification due to version creation, not reduces it.
Final Answer:
Option A -> Option A
Quick Check:
MVCC trades off storage and cleanup overhead for concurrency benefits [OK]
Hint: MVCC trades storage and cleanup overhead for non-blocking reads
Common Mistakes:
Assuming MVCC removes all contention
Confusing snapshot isolation with serializability
Believing MVCC reduces write amplification
5. What is a common trade-off or limitation of using strict Two-Phase Locking (2PL) in high-concurrency database systems?
medium
A. Strict 2PL can cause increased waiting and deadlocks, reducing concurrency
B. Strict 2PL eliminates deadlocks entirely, improving throughput
C. Strict 2PL allows transactions to release locks early, improving performance
D. Strict 2PL requires no lock compatibility checks, simplifying implementation
Solution
Step 1: Understand strict 2PL behavior
Strict 2PL holds exclusive locks until commit, which can increase waiting times.
Step 2: Analyze deadlock potential
Because locks are held longer, deadlocks can occur more frequently, reducing concurrency.
Step 3: Evaluate options
B is incorrect; strict 2PL does not eliminate deadlocks. C is incorrect; locks are not released early. D is wrong; lock compatibility checks are essential. A correctly identifies the trade-off.
Final Answer:
Option A -> Option A
Quick Check:
Strict 2PL trades off concurrency for serializability, increasing deadlock risk.
Hint: Strict 2PL trades concurrency for serializability, risking deadlocks [OK]
Common Mistakes:
Believing strict 2PL prevents deadlocks
Thinking locks can be released early in strict 2PL
Ignoring lock compatibility checks
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.