Joins
JOIN 子句,也称为连接,可根据某些条件(如某些列的值是否相等)将两个或多个表表达式的结果组合起来。
对于流式查询中的常规相等连接,临时连接的结果是无界的。如果连接结果太大,查询性能可能会受到影响。因此,您可能需要考虑有时间限制的连接类型,如间隔连接(interval joins)和时态连接(temporal joins)。
常规连接
RisingWave 支持以下常规连接类型:
- 内连接
- 左(外)连接
- 右(外)连接
- 完全(外)连接
内连接
内连接可返回左表和右表表达式中满足指定连接条件的行。不满足条件的行将从结果集中排除。
INNER JOIN 的句法如下:
<table_expression> INNER JOIN <table_expression> ON <join_conditions>;
<table_expression> INNER JOIN <table_expression> USING (<col_name>, <col_name>, ...);
<table_expression> NATURAL [ INNER ] JOIN <table_expression>;
左外连接(Left outer join)
左外连接(或简称左连接)可返回左表表达式的所有行以及右表表达式的匹配行。如果没有找到匹配项,将使用右表的列填充 NULL 值。
LEFT (OUTER) JOIN 的句法如下:
<table_expression> LEFT [ OUTER ] JOIN <table_expression> ON <join_conditions>;
<table_expression> LEFT [ OUTER ] JOIN <table_expression> USING (<col_name>, <col_name>, ...);
<table_expression> NATURAL LEFT [ OUTER ] JOIN <table_expression>;
右外连接(Right outer join)
右外连接(或简称右连接)可返回右表表达式的所有行以及左表表达式的匹配行。如果没有找到匹配项,左表表达式中的列将返回 NULL 值。
RIGHT (OUTER) JOIN 的句法如下:
<table_expression> RIGHT [ OUTER ] JOIN <table_expression> ON <join_conditions>;
<table_expression> RIGHT [ OUTER ] JOIN <table_expression> USING (<col_name>, <col_name>, ...);
<table_expression> NATURAL RIGHT [ OUTER ] JOIN <table_expression>;
完全外连接(Full outer join)
完全外连接(或简称完全连接)可在左表表达式或右表表达式中找到匹配项时返回所有行。如果没有找到匹配项,表表达式中没有找到匹配项的列将返回 NULL 值。
<table_expression> FULL [ OUTER ] JOIN <table_expression> ON <join_conditions>;
<table_expression> FULL [ OUTER ] JOIN <table_expression> USING (<col_name>, <col_name>, ...);
<table_expression> NATURAL FULL [ OUTER ] JOIN <table_expression>;
时间窗口连接(Windows join)
在常规连接中(即没有时间属性的连接),连接状态可能会无限增长。如果您只需要获取两个 source 的窗口结果,可以将 source 中的数据分段到时间窗口中,然后连接两个 source 中匹配的窗口。要创建窗口连接,必须使用相同的时间窗口函数,并且窗口大小必须相同。
窗口连接的句法是:
<time_window_expression> JOIN <time_window_expression> ON <join_conditions>;
其中一个 join_conditions
必须是基于两个表表达式水印的相等条件。有关 <time_window_expression>
的句法,请参阅时间窗口函数。
例如,假设您有以下两个 source:
CREATE SOURCE s1 (
id int,
value int,
ts TIMESTAMP,
WATERMARK FOR ts AS ts - INTERVAL '20' SECOND
) WITH (connector = 'datagen');
CREATE SOURCE s2 (
id int,
value int,
ts TIMESTAMP,
WATERMARK FOR ts AS ts - INTERVAL '20' SECOND
) WITH (connector = 'datagen');
您可以使用以下语句将它们连接起来:
CREATE MATERIALIZED VIEW window_join AS
SELECT s1.id AS id1,
s1.value AS value1,
s2.id AS id2,
s2.value AS value2
FROM TUMBLE(s1, ts, interval '1' MINUTE)
JOIN TUMBLE(s2, ts, interval '1' MINUTE)
ON s1.id = s2.id and s1.window_start = s2.window_start;
间隔连接(Interval join)
窗口连接要求两个 source 具有相同的窗口类型和窗口大小。在某些情况下,这一要求可能过于严格。如果要连接两个有一定时间偏移的 source,可以根据水印指定可接受的间隔范围,创建间隔连接。
间隔连接的句法是:
<table_expression> JOIN <table_expression> ON <equality_join_condition> AND <interval_condition> ...;
在间隔连接中,interval_condtion
必须是基于水印的范围。
例如,对于上一节中使用的 source s1
和 s2
,可以创建一个间隔连接:
CREATE MATERIALIZED VIEW interval_join AS
SELECT s1.id AS id1,
s1.value AS value1,
s2.id AS id2,
s2.value AS value2
FROM s1 JOIN s2
ON s1.id = s2.id and s1.ts between s2.ts and s2.ts + INTERVAL '1' MINUTE;
处理时间时态连接(Process-time temporal join)
时态连接通常用于扩大事实表。它的优点是不需要 RisingWave 维护连接状态,因此适合维度表不更新或维度表更新不影响先前连接结果的情况。为了进一步提高性能,可以使用维度表的索引与事实表形成连接。
句法
<table_expression> [ LEFT | INNER ] JOIN <table_expression> FOR SYSTEM_TIME AS OF PROCTIME() ON <join_conditions>;
请注意
- 左表表达式是仅附加数据的表或 Source。
- 右表表达式是表、索引或物化视图。
- 右表表达式中包含
FOR SYSTEM_TIME AS OF PROCTIME()
这一进程时间句法。 - 连接类型是 INNER JOIN 或 LEFT JOIN。
- 连接条件包括右表表达式的主键。
示例
如果你有一个包含如下消息的仅追加数据的流:
transaction_id | product_id | quantity | sale_date | process_time |
---|---|---|---|---|
1 | 101 | 3 | 2023-06-18 | 2023-06-18 10:15:00 |
2 | 102 | 2 | 2023-06-19 | 2023-06-19 15:30:00 |
3 | 101 | 1 | 2023-06-20 | 2023-06-20 11:45:00 |
以及一个版本表 products
:
id | product_name | price | valid_from | valid_to |
---|---|---|---|---|
101 | Product A | 20 | 2023-06-01 00:00:00 | 2023-06-15 23:59:59 |
101 | Product A | 25 | 2023-06-16 00:00:00 | 2023-06-19 23:59:59 |
101 | Product A | 22 | 2023-06-20 00:00:00 | NULL |
102 | Product B | 15 | 2023-06-01 00:00:00 | NULL |
对于同一产品 ID,产品名称或价格会不时更新。
您可以使用时间连接从表 products
中获取最新的产品名称和价格,并形成一个更宽的表。为进一步提高性能,可以为表 products
创建一个索引,然后使用该索引连接 sales
。
SELECT transaction_id, product_id, quantity, sale_date, product_name, price
FROM sales
JOIN products FOR SYSTEM_TIME AS OF PROCTIME()
ON product_id = id
transaction_id | product_id | quantity | sale_date | product_name | price |
---|---|---|---|---|---|
1 | 101 | 3 | 2023-06-18 | Product A | 25 |
2 | 102 | 2 | 2023-06-19 | Product B | 15 |
3 | 101 | 1 | 2023-06-20 | Product A | 22 |