1. 什么是Lateral查询?
Lateral查询(也称为横向关联查询)是一种特殊的子查询,允许子查询中引用外层查询的列(即关联引用),并在执行时逐行对外层查询的每一行数据执行子查询。 语法上通常使用关键字 LATERAL
(部分数据库如PostgreSQL支持),或通过特定语法隐式实现(如Oracle的CROSS APPLY
/OUTER APPLY
)。
-- 显式LATERAL(PostgreSQL)
SELECT t1.id, t2.amount
FROM t1,
LATERAL (SELECT amount FROM t2 WHERE t2.id = t1.id) t2;
-- 隐式实现(Oracle/SQL Server)
SELECT t1.id, t2.amount
FROM t1
CROSS APPLY (SELECT amount FROM t2 WHERE t2.id = t1.id) t2;
Lateral查询主要用于以下场景:
当子查询需要基于外层查询的当前行动态计算时,必须使用Lateral。 案例:计算每个用户的最近一笔订单金额。
SELECT u.user_id, o.order_amount
FROM users u,
LATERAL (
SELECT amount AS order_amount
FROM orders
WHERE user_id = u.user_id
ORDER BY order_date DESC
LIMIT 1 -- 每行用户只取最新订单
) o;
说明: 普通JOIN无法实现“每行限制结果”(如LIMIT 1
),而Lateral子查询会为每个user_id
单独执行。
解析嵌套数据结构(如JSON数组、XML)时,需将数组元素展开为多行。 案例:展开用户标签数组。
SELECT u.user_id, tag.tag_name
FROM users u,
LATERAL jsonb_array_elements(u.tags) AS tag(tag_name);
说明: jsonb_array_elements
函数为每个用户的标签数组生成多行,依赖外层查询的u.tags
字段。
当聚合逻辑需要依赖外层条件时,Lateral比普通JOIN更直观。 案例:统计每个用户消费金额超过平均值的订单数。
SELECT u.user_id, COUNT(o.order_id) AS high_value_orders
FROM users u,
LATERAL (
SELECT order_id
FROM orders
WHERE user_id = u.user_id AND amount > (
SELECT AVG(amount) FROM orders WHERE user_id = u.user_id
)
) o
GROUP BY u.user_id;
特性 | Lateral查询 | 普通JOIN(LEFT JOIN/INNER JOIN) |
---|---|---|
执行逻辑 | 逐行执行子查询,依赖外层当前行数据 | 先完成所有表关联,再过滤或聚合 |
关联引用 | 子查询可引用外层列 | 子查询不能直接引用外层列(需通过JOIN条件) |
性能 | 可能较慢(N次子查询) | 通常更快(单次扫描+哈希连接) |
适用操作 | 支持LIMIT、窗口函数等逐行操作 | 无法在JOIN中直接使用LIMIT |
典型语法 | LATERAL、CROSS APPLY、OUTER APPLY | JOIN ... ON、WHERE |
4. 何时选择Lateral查询?
LIMIT
、窗口函数)。 LIMIT
、JSON展开)。 在实际应用中,优先尝试用普通JOIN优化,仅在必要时使用Lateral。