产品概述
应用场景
产品架构
实例类型
兼容性说明
使用规范建议
JOIN 语句进行多表连接查询,包括各种连接类型、连接算法的使用。SELECTo.o_orderkey,o.o_orderdate,o.o_totalprice,c.c_name,c.c_mktsegmentFROM orders oINNER JOIN customer c ON o.o_custkey = c.c_custkey;
customer 表中存在对应客户的订单才会被返回。SELECTc.c_name,o.o_orderkey,o.o_orderdate,l.l_partkey,l.l_quantity,l.l_extendedpriceFROM customer cINNER JOIN orders o ON c.c_custkey = o.o_custkeyINNER JOIN lineitem l ON o.o_orderkey = l.l_orderkeyWHERE o.o_orderdate BETWEEN '1995-01-01' AND '1995-03-31'ORDER BY l.l_extendedprice DESCLIMIT 20;
INNER JOIN,没有下过订单的客户不会出现在结果中。如果需要包含没有订单的客户,应使用 LEFT JOIN。NULL。SELECTc.c_custkey,c.c_name,c.c_mktsegment,COUNT(o.o_orderkey) AS order_countFROM customer cLEFT JOIN orders o ON c.c_custkey = o.o_custkeyGROUP BY c.c_custkey, c.c_name, c.c_mktsegmentORDER BY order_count ASCLIMIT 20;
INNER JOIN 不同,即使某个客户在 orders 表中没有任何记录,该客户仍然会出现在结果中,其 order_count 为0。SELECT c.c_custkey, c.c_name, c.c_phoneFROM customer cLEFT JOIN orders o ON c.c_custkey = o.o_custkeyWHERE o.o_orderkey IS NULL;
NOT EXISTS 子查询,但在某些场景下执行效率更高:-- 等价写法SELECT c_custkey, c_name, c_phoneFROM customer cWHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.o_custkey = c.c_custkey);
NULL。其逻辑与 LEFT JOIN 对称。SELECTn.n_name AS nation_name,COUNT(c.c_custkey) AS customer_countFROM customer cRIGHT JOIN nation n ON c.c_nationkey = n.n_nationkeyGROUP BY n.n_nameORDER BY customer_count DESC;
LEFT JOIN 代替 RIGHT JOIN,只需调换表的顺序即可。这样可以保持 SQL 风格一致,提高可读性。SELECTn.n_name AS nation_name,COUNT(c.c_custkey) AS customer_countFROM nation nLEFT JOIN customer c ON c.c_nationkey = n.n_nationkeyGROUP BY n.n_nameORDER BY customer_count DESC;
SELECTr.r_name AS region_name,seg.segment_nameFROM region rCROSS JOIN (SELECT DISTINCT c_mktsegment AS segment_nameFROM customer) segORDER BY r.r_name, seg.segment_name;
EXISTS 或 IN 子查询来表达。SELECT c.c_custkey, c.c_name, c.c_acctbalFROM customer cWHERE EXISTS (SELECT 1 FROM orders oWHERE o.o_custkey = c.c_custkey);
IN 写法:SELECT c_custkey, c_name, c_acctbalFROM customerWHERE c_custkey IN (SELECT o_custkey FROM orders);
INNER JOIN 不同,左半连接不会因右表存在多条匹配而产生重复行。例如一个客户有10个订单,INNER JOIN 会返回10行,而左半连接只返回1行。JOIN 关键字,而是在 FROM 子句中列出多张表,并在 WHERE 子句中指定连接条件。隐式连接的行为等同于 INNER JOIN。SELECTc.c_name,o.o_orderkey,o.o_totalpriceFROM customer c, orders oWHERE c.c_custkey = o.o_custkeyAND o.o_orderdate >= '1995-01-01'ORDER BY o.o_totalprice DESCLIMIT 10;
JOIN ... ON 语法代替隐式连接。显式语法将连接条件与过滤条件分离,SQL 的意图更加清晰,也更易于维护。-- 典型的 Nested Loop Join 场景-- orders 作为外表,customer 通过主键 c_custkey 作为内表SELECTo.o_orderkey,o.o_totalprice,c.c_nameFROM orders oINNER JOIN customer c ON o.o_custkey = c.c_custkeyWHERE o.o_orderdate = '1995-03-15';
orders 表经过 o_orderdate 过滤后行数较少,作为驱动表;customer 表的 c_custkey 是主键,作为被驱动表。BKA 会将过滤后的 o_custkey 值批量发送,一次性在 customer 表中查找匹配行。= 条件)-- 典型的 Hash Join 场景-- 两张大表的等值连接,且连接列无索引SELECTl.l_orderkey,l.l_extendedprice,l.l_discount,p.p_name,p.p_typeFROM lineitem lINNER JOIN part p ON l.l_partkey = p.p_partkeyWHERE p.p_type LIKE '%BRASS%';
因素 | Nested Loop Join (BKA) | Hash Join |
索引依赖 | 需要内表连接列上有索引 | 不依赖索引 |
数据量 | 适合外表较小、内表较大的场景 | 适合两表都较大的场景 |
内存消耗 | 较低,按批次处理 | 较高,需要在内存中构建哈希表 |
连接类型 | 等值和非等值连接 | 仅支持等值连接 |
EXPLAIN 可以查看优化器选择的连接算法:EXPLAIN SELECTo.o_orderkey, c.c_nameFROM orders oINNER JOIN customer c ON o.o_custkey = c.c_custkeyWHERE o.o_orderdate = '1995-03-15';
-- 优化器会自动决定 customer、orders、lineitem 的连接顺序SELECTc.c_name,o.o_orderdate,l.l_extendedpriceFROM customer cINNER JOIN orders o ON c.c_custkey = o.o_custkeyINNER JOIN lineitem l ON o.o_orderkey = l.l_orderkeyWHERE c.c_mktsegment = 'BUILDING'AND o.o_orderdate < '1995-03-15'AND l.l_shipdate > '1995-03-15';
SELECT /*+ JOIN_ORDER(o, c, l) */c.c_name,o.o_orderdate,l.l_extendedpriceFROM customer cINNER JOIN orders o ON c.c_custkey = o.o_custkeyINNER JOIN lineitem l ON o.o_orderkey = l.l_orderkeyWHERE c.c_mktsegment = 'BUILDING'AND o.o_orderdate < '1995-03-15'AND l.l_shipdate > '1995-03-15';
JOIN_ORDER(o, c, l) 强制优化器严格按 orders > customer > lineitem 的顺序执行连接,忽略 SQL 中的表书写位置。SELECT /*+ JOIN_PREFIX(o, c) */c.c_name,o.o_orderdate,l.l_extendedpriceFROM customer cINNER JOIN orders o ON c.c_custkey = o.o_custkeyINNER JOIN lineitem l ON o.o_orderkey = l.l_orderkeyWHERE c.c_mktsegment = 'BUILDING'AND o.o_orderdate < '1995-03-15'AND l.l_shipdate > '1995-03-15';
文档反馈