aboutsummaryrefslogtreecommitdiff
path: root/content/posts/postgres-aggregates-correction/queries.sql
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-03-29 15:51:33 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-03-29 15:51:33 +0200
commit125f2bd4bec733e79ef8596a88b38497e66037c4 (patch)
tree5f094583d7b8daf4e021ef7f831e56f7d57bbc3c /content/posts/postgres-aggregates-correction/queries.sql
parentd6c5682628d69e3e8281a6ebcba14eba9f48e2c3 (diff)
Consolidate results
Diffstat (limited to 'content/posts/postgres-aggregates-correction/queries.sql')
-rw-r--r--content/posts/postgres-aggregates-correction/queries.sql183
1 files changed, 183 insertions, 0 deletions
diff --git a/content/posts/postgres-aggregates-correction/queries.sql b/content/posts/postgres-aggregates-correction/queries.sql
new file mode 100644
index 0000000..ce8bb55
--- /dev/null
+++ b/content/posts/postgres-aggregates-correction/queries.sql
@@ -0,0 +1,183 @@
+-- ============================================================
+-- postgres-aggregates-correction: benchmark queries
+-- Run each block separately and save the EXPLAIN output.
+-- ============================================================
+
+-- -------------------------------------------------------
+-- 1. Subquery — count(id) — no filter [ORIGINAL, baseline]
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(id) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(id) FROM orders WHERE product_id = products.id) AS num_orders
+FROM products;
+
+
+-- -------------------------------------------------------
+-- 2. Subquery — count(*) — no filter [THE FIX]
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(*) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(*) FROM orders WHERE product_id = products.id) AS num_orders
+FROM products;
+
+
+-- -------------------------------------------------------
+-- 3. CTE (merging) — count(id) — no filter
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+WITH product_reviews AS (
+ SELECT product_id, COUNT(id) AS num_reviews
+ FROM reviews
+ GROUP BY product_id
+),
+product_orders AS (
+ SELECT product_id, COUNT(id) AS num_orders
+ FROM orders
+ GROUP BY product_id
+)
+SELECT
+ products.id,
+ products.name,
+ COALESCE(product_reviews.num_reviews, 0) AS num_reviews,
+ COALESCE(product_orders.num_orders, 0) AS num_orders
+FROM products
+LEFT JOIN product_reviews ON products.id = product_reviews.product_id
+LEFT JOIN product_orders ON products.id = product_orders.product_id;
+
+
+-- -------------------------------------------------------
+-- 4. Subquery — count(*) — root filter (price > 900)
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(*) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(*) FROM orders WHERE product_id = products.id) AS num_orders
+FROM products
+WHERE products.price > 900;
+
+
+-- -------------------------------------------------------
+-- 5. CTE (merging) — count(id) — root filter (price > 900)
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+WITH product_reviews AS (
+ SELECT product_id, COUNT(id) AS num_reviews
+ FROM reviews
+ GROUP BY product_id
+),
+product_orders AS (
+ SELECT product_id, COUNT(id) AS num_orders
+ FROM orders
+ GROUP BY product_id
+)
+SELECT
+ products.id,
+ products.name,
+ COALESCE(product_reviews.num_reviews, 0) AS num_reviews,
+ COALESCE(product_orders.num_orders, 0) AS num_orders
+FROM products
+LEFT JOIN product_reviews ON products.id = product_reviews.product_id
+LEFT JOIN product_orders ON products.id = product_orders.product_id
+WHERE products.price > 900;
+
+
+-- -------------------------------------------------------
+-- 6. Subquery — count(*) — leaf filter (customer_name ilike '%0')
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(*) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(*) FROM orders WHERE product_id = products.id AND customer_name ILIKE '%0') AS num_orders
+FROM products;
+
+
+-- -------------------------------------------------------
+-- 7. CTE (merging) — count(id) — leaf filter (customer_name ilike '%0')
+-- -------------------------------------------------------
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+WITH product_reviews AS (
+ SELECT product_id, COUNT(id) AS num_reviews
+ FROM reviews
+ GROUP BY product_id
+),
+product_orders AS (
+ SELECT product_id, COUNT(id) AS num_orders
+ FROM orders
+ WHERE customer_name ILIKE '%0'
+ GROUP BY product_id
+)
+SELECT
+ products.id,
+ products.name,
+ COALESCE(product_reviews.num_reviews, 0) AS num_reviews,
+ COALESCE(product_orders.num_orders, 0) AS num_orders
+FROM products
+LEFT JOIN product_reviews ON products.id = product_reviews.product_id
+LEFT JOIN product_orders ON products.id = product_orders.product_id;
+
+
+-- ============================================================
+-- DISK-THROTTLED PASS (run with Docker: shared_buffers=16MB,
+-- blkio capped at 125MB/s read — see docker-compose snippet)
+-- Run DISCARD ALL between queries to flush caches.
+-- ============================================================
+
+-- -------------------------------------------------------
+-- D1. Subquery — count(id) — no filter [Bitmap Heap Scan expected]
+-- -------------------------------------------------------
+DISCARD ALL;
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(id) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(id) FROM orders WHERE product_id = products.id) AS num_orders
+FROM products;
+
+
+-- -------------------------------------------------------
+-- D2. Subquery — count(*) — no filter [Index Only Scan expected]
+-- -------------------------------------------------------
+DISCARD ALL;
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+SELECT
+ products.id,
+ products.name,
+ (SELECT COUNT(*) FROM reviews WHERE product_id = products.id) AS num_reviews,
+ (SELECT COUNT(*) FROM orders WHERE product_id = products.id) AS num_orders
+FROM products;
+
+
+-- -------------------------------------------------------
+-- D3. CTE (merging) — count(id) — no filter
+-- -------------------------------------------------------
+DISCARD ALL;
+EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)
+WITH product_reviews AS (
+ SELECT product_id, COUNT(id) AS num_reviews
+ FROM reviews
+ GROUP BY product_id
+),
+product_orders AS (
+ SELECT product_id, COUNT(id) AS num_orders
+ FROM orders
+ GROUP BY product_id
+)
+SELECT
+ products.id,
+ products.name,
+ COALESCE(product_reviews.num_reviews, 0) AS num_reviews,
+ COALESCE(product_orders.num_orders, 0) AS num_orders
+FROM products
+LEFT JOIN product_reviews ON products.id = product_reviews.product_id
+LEFT JOIN product_orders ON products.id = product_orders.product_id;