Skip to main content

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 s1s2,可以创建一个间隔连接:

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_idproduct_idquantitysale_dateprocess_time
110132023-06-182023-06-18 10:15:00
210222023-06-192023-06-19 15:30:00
310112023-06-202023-06-20 11:45:00

以及一个版本表 products

idproduct_namepricevalid_fromvalid_to
101Product A202023-06-01 00:00:002023-06-15 23:59:59
101Product A252023-06-16 00:00:002023-06-19 23:59:59
101Product A222023-06-20 00:00:00NULL
102Product B152023-06-01 00:00:00NULL

对于同一产品 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_idproduct_idquantitysale_dateproduct_nameprice
110132023-06-18Product A25
210222023-06-19Product B15
310112023-06-20Product A22