Join

更新时间:
复制为 MD 格式

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

联接类型。取值如下:

  • INNER JOIN(默认):只返回两表中满足联接条件的行。

  • LEFT OUTER JOIN:返回左表的所有行,并按联接条件匹配右表数据。右表中无匹配行时,对应列填充 NULL。

  • RIGHT OUTER JOIN:返回右表的所有行,并按联接条件匹配左表数据。左表中无匹配行时,对应列填充 NULL。

  • CROSS JOIN:返回两表的笛卡尔积,左表每行与右表所有行两两组合。

join_condition

指定两张表进行行匹配的联接列。

例如,以下 SQL 语句对 table_1.col_Atable_2.col_B 相等的行进行联接:

SELECT * FROM table_1 JOIN table_2 on table_1.col_A = table_2.col_B;

如果两表的联接列名相同,可以用 USING ( join_column [, ...] ) 简化 SQL 语句。例如,以下两条 SQL 语句等价:

SELECT * FROM table_1 JOIN table_2 
    on table_1.col_A = table_2.col_A and table_1.col_B = table_2.col_B;

使用 USING 简化后:

SELECT * FROM table_1 JOIN table_2 USING (col_A, col_B);

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 语句中的某张表缺少合适的索引时,过滤条件会触发全表扫描。为联接列和过滤列添加索引可以显著提升查询速度。

示例

以下示例基于 orderscustomers 两张表:

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 |
    +----------+-------------+------------+--------------+-------------+---------------+----------------+