Lateral Join - Vòng lặp “cho từng dòng” trong SQL
Tính năng cực kỳ mạnh mà ít developer biết. Normal JOIN chỉ link rows dựa trên condition - không thể control bao nhiêu rows từ mỗi nhóm. Lateral Join giải quyết điều này.
Use case kinh điển: “Top N per group”
Dashboard hiển thị mỗi customer + 3 đơn hàng gần nhất:
SELECT customers.*, recent_sales.*
FROM customers
LEFT JOIN LATERAL (
SELECT * FROM sales
WHERE sales.customer_id = customers.id
ORDER BY created_at DESC
LIMIT 3
) AS recent_sales ON true;
-- Lateral subquery chạy cho MỖI customer:
-- Customer 1 → SELECT TOP 3 sales WHERE customer_id = 1
-- Customer 2 → SELECT TOP 3 sales WHERE customer_id = 2
-- Index cần: (customer_id, created_at DESC) trên bảng sales
-- → Mỗi lateral subquery chỉ cần đọc 3 index entriesSo sánh với cách truyền thống (ROW_NUMBER)
-- Cách cũ: load TẤT CẢ sales, đánh số thứ tự, filter
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY customer_id
ORDER BY created_at DESC) as rn
FROM sales
)
SELECT * FROM customers JOIN ranked ON ... WHERE rn <= 3;
-- Phải đọc TOÀN BỘ bảng sales rồi mới filter → chậm hơn nhiềuLateral Join cũng hoạt động cho: “lấy giá trị mới nhất cho mỗi group”, “lấy aggregate cho mỗi entity”, v.v.
Liên quan
- Nested Loop Join - lateral là loop tường minh mà bạn control được
- ORDER BY và Index - index (customer_id, created_at DESC) tận dụng scan + LIMIT
- Quét một hướng - vì sao mỗi subquery chỉ đọc 3 entries