Join 功能支持将两张或多张表按联接条件进行连接,返回满足条件的数据行。
注意事项
本文中,左表指 JOIN 关键词左侧的表,右表指 JOIN 关键词右侧的表。
例如,以下 SQL 语句中,table_1 为左表,table_2 为右表。
SELECT * FROM table_1 JOIN table_2 on ......;
语法
table_references join_type table_references [ ON join_condition | USING ( join_column [, ...] ) ]
table_references : {
table_name [ [ AS ] alias_name ]
| select_statement
}
join_type : {
[ INNER ] JOIN
| LEFT [ OUTER ] JOIN
| RIGHT [ OUTER ] JOIN
| CROSS JOIN
}
参数
|
参数 |
是否必选 |
说明 |
|
table_references |
是 |
联接的目标表,可以是表名(可附带别名)或 SELECT 子查询。 表在 JOIN 关键词的左侧还是右侧,决定了它是左表还是右表。 |
|
join_type |
是 |
联接类型。取值如下:
|
|
join_condition |
是 |
指定两张表进行行匹配的联接列。 例如,以下 SQL 语句对
如果两表的联接列名相同,可以用
使用 USING 简化后:
|
Join 算法
表格存储支持 INDEX JOIN 和 HASH JOIN 两种 Join 算法,默认使用 INDEX JOIN。当右表的联接列不满足 INDEX JOIN 的索引条件时,系统自动切换为 HASH JOIN。
INDEX JOIN(默认):从左表读取数据,利用右表的索引或主键查找匹配行进行联接。详细说明请参见 INDEX JOIN。
HASH JOIN:从左表读取数据构建哈希表,再用右表的行探测哈希表判断是否匹配。详细说明请参见 HASH JOIN。
INDEX JOIN
INDEX JOIN 对右表的联接列有索引要求,对左表无要求。
通过主键或二级索引访问右表时,联接列必须满足最左匹配原则。
通过多元索引访问右表时,联接列必须全部命中某一个多元索引,且右表上的其他过滤条件也必须能下推到该多元索引。
当需要联接的行数较少(例如左表数据量本身较小,或经过过滤后输出行数较少)且右表满足 INDEX JOIN 索引条件时,INDEX JOIN 通常有更好的性能。对于 INNER JOIN,将数据量更少(或过滤后行数更少)的表放在左侧,可以进一步提升性能。
HASH JOIN
HASH JOIN 无索引限制,当右表不满足 INDEX JOIN 的使用条件时,系统自动选择 HASH JOIN。
当需要联接的行数较多时,HASH JOIN 通常有更好的性能。对于 INNER JOIN,同样建议将数据量更少(或过滤后行数更少)的表放在左侧。
算法选择建议
-
INDEX JOIN 的使用条件:右表的联接列必须满足以下索引条件之一:
通过主键或二级索引访问时,联接列满足最左匹配原则。
通过多元索引访问时,联接列全部命中该多元索引,且过滤条件可下推。
右表缺少合适的索引时,INDEX JOIN 会退化为全表扫描,性能优势丧失。
INNER JOIN 的左右表选择:将数据量更少(或使用过滤条件后输出行数更少)的表放在 JOIN 关键词左侧。左表直接驱动联接循环,左表越小,整体执行越快。
INDEX JOIN vs. HASH JOIN:联接行数少时,INDEX JOIN 性能更好;联接行数多时,HASH JOIN 性能更好。
通过索引加速联接:当 JOIN 语句中的某张表缺少合适的索引时,过滤条件会触发全表扫描。为联接列和过滤列添加索引可以显著提升查询速度。
示例
以下示例基于 orders 和 customers 两张表:
SELECT * FROM orders;
+----------+-------------+------------+--------------+
| order_id | customer_id | order_date | order_amount |
+----------+-------------+------------+--------------+
| 1001 | 1 | 2023-01-01 | 50 |
| 1002 | 2 | 2023-01-02 | 80 |
| 1003 | 3 | 2023-01-03 | 180 |
| 1004 | 4 | 2023-01-04 | 220 |
| 1005 | 6 | 2023-01-05 | 250 |
+----------+-------------+------------+--------------+
SELECT * FROM customers;
+-------------+---------------+----------------+
| customer_id | customer_name | customer_phone |
+-------------+---------------+----------------+
| 1 | Alice | 11111111111 |
| 2 | Bob | 22222222222 |
| 3 | Carol | 33333333333 |
| 4 | David | 44444444444 |
| 5 | Eve | 55555555555 |
+-------------+---------------+----------------+
-
示例一:INNER JOIN
只返回两表中
customer_id匹配的订单。订单 1005(customer_id = 6)因在customers表中无对应记录而被排除。SELECT * FROM orders JOIN customers ON orders.customer_id = customers.customer_id;当两表的联接列名相同时,可以用 USING 子句简化:
SELECT * FROM orders JOIN customers USING(customer_id);返回结果:
+----------+-------------+------------+--------------+-------------+---------------+----------------+ | order_id | customer_id | order_date | order_amount | customer_id | customer_name | customer_phone | +----------+-------------+------------+--------------+-------------+---------------+----------------+ | 1001 | 1 | 2023-01-01 | 50 | 1 | Alice | 11111111111 | | 1002 | 2 | 2023-01-02 | 80 | 2 | Bob | 22222222222 | | 1003 | 3 | 2023-01-03 | 180 | 3 | Carol | 33333333333 | | 1004 | 4 | 2023-01-04 | 220 | 4 | David | 44444444444 | +----------+-------------+------------+--------------+-------------+---------------+----------------+ -
示例二:LEFT JOIN
返回所有订单,包括订单 1005(
customer_id = 6,在customers表中无匹配记录)。无匹配的customers列填充 NULL。SELECT * FROM orders LEFT JOIN customers ON orders.customer_id = customers.customer_id;使用 USING 子句等价写法:
SELECT * FROM orders LEFT JOIN customers USING(customer_id);返回结果:
+----------+-------------+------------+--------------+-------------+---------------+----------------+ | order_id | customer_id | order_date | order_amount | customer_id | customer_name | customer_phone | +----------+-------------+------------+--------------+-------------+---------------+----------------+ | 1001 | 1 | 2023-01-01 | 50 | 1 | Alice | 11111111111 | | 1002 | 2 | 2023-01-02 | 80 | 2 | Bob | 22222222222 | | 1003 | 3 | 2023-01-03 | 180 | 3 | Carol | 33333333333 | | 1004 | 4 | 2023-01-04 | 220 | 4 | David | 44444444444 | | 1005 | 6 | 2023-01-05 | 250 | NULL | NULL | NULL | +----------+-------------+------------+--------------+-------------+---------------+----------------+ -
示例三:CROSS JOIN
返回两表的笛卡尔积,共 5 × 5 = 25 行。
SELECT * FROM orders CROSS JOIN customers;返回结果:
+----------+-------------+------------+--------------+-------------+---------------+----------------+ | order_id | customer_id | order_date | order_amount | customer_id | customer_name | customer_phone | +----------+-------------+------------+--------------+-------------+---------------+----------------+ | 1001 | 1 | 2023-01-01 | 50 | 1 | Alice | 11111111111 | | 1002 | 2 | 2023-01-02 | 80 | 1 | Alice | 11111111111 | | 1003 | 3 | 2023-01-03 | 180 | 1 | Alice | 11111111111 | | 1004 | 4 | 2023-01-04 | 220 | 1 | Alice | 11111111111 | | 1005 | 6 | 2023-01-05 | 250 | 1 | Alice | 11111111111 | | 1001 | 1 | 2023-01-01 | 50 | 2 | Bob | 22222222222 | | 1002 | 2 | 2023-01-02 | 80 | 2 | Bob | 22222222222 | | 1003 | 3 | 2023-01-03 | 180 | 2 | Bob | 22222222222 | | 1004 | 4 | 2023-01-04 | 220 | 2 | Bob | 22222222222 | | 1005 | 6 | 2023-01-05 | 250 | 2 | Bob | 22222222222 | | 1001 | 1 | 2023-01-01 | 50 | 3 | Carol | 33333333333 | | 1002 | 2 | 2023-01-02 | 80 | 3 | Carol | 33333333333 | | 1003 | 3 | 2023-01-03 | 180 | 3 | Carol | 33333333333 | | 1004 | 4 | 2023-01-04 | 220 | 3 | Carol | 33333333333 | | 1005 | 6 | 2023-01-05 | 250 | 3 | Carol | 33333333333 | | 1001 | 1 | 2023-01-01 | 50 | 4 | David | 44444444444 | | 1002 | 2 | 2023-01-02 | 80 | 4 | David | 44444444444 | | 1003 | 3 | 2023-01-03 | 180 | 4 | David | 44444444444 | | 1004 | 4 | 2023-01-04 | 220 | 4 | David | 44444444444 | | 1005 | 6 | 2023-01-05 | 250 | 4 | David | 44444444444 | | 1001 | 1 | 2023-01-01 | 50 | 5 | Eve | 55555555555 | | 1002 | 2 | 2023-01-02 | 80 | 5 | Eve | 55555555555 | | 1003 | 3 | 2023-01-03 | 180 | 5 | Eve | 55555555555 | | 1004 | 4 | 2023-01-04 | 220 | 5 | Eve | 55555555555 | | 1005 | 6 | 2023-01-05 | 250 | 5 | Eve | 55555555555 | +----------+-------------+------------+--------------+-------------+---------------+----------------+