在 BigQuery 的 GoogleSQL 中,WITH 子句包含一或多個通用資料表運算式 (CTE),您可以在查詢運算式中參照這些運算式。CTE 可以是非遞迴、遞迴或兩者。RECURSIVE
關鍵字會在 WITH 子句 (WITH RECURSIVE) 中啟用遞迴。
遞迴 CTE 可以參照自身、先前的 CTE 或後續的 CTE。非遞迴 CTE 只能參照先前的 CTE,不能參照自身。遞迴 CTE 會持續執行,直到找不到新結果為止,而非遞迴 CTE 則只會執行一次。因此,遞迴 CTE 通常用於查詢階層式資料和圖形資料。
舉例來說,假設有一個圖表,其中每一列代表一個節點,可連結至其他節點。如要找出特定開始節點中所有可連線節點的遞移閉包,但不知道跳躍次數上限,您需要在查詢中使用遞迴 CTE (WITH RECURSIVE)。遞迴查詢會從開始節點的基本情況開始,每個步驟都會計算從先前步驟中所有節點可連線的新節點。找不到新節點時,查詢就會結束。
不過,遞迴 CTE 的運算成本可能很高,因此使用前請先參閱本指南和 GoogleSQL 參考文件的WITH 子句部分。
建立遞迴 CTE
如要在 GoogleSQL 中建立遞迴 CTE,請使用 WITH RECURSIVE 子句,如下列範例所示:
WITH RECURSIVE
CTE_1 AS (
(SELECT 1 AS iteration UNION ALL SELECT 1 AS iteration)
UNION ALL
SELECT iteration + 1 AS iteration FROM CTE_1 WHERE iteration < 3
)
SELECT iteration FROM CTE_1
ORDER BY 1 ASC
上述範例會產生下列結果:
/*-----------+
| iteration |
+-----------+
| 1 |
| 1 |
| 2 |
| 2 |
| 3 |
| 3 |
+-----------*/
遞迴 CTE 包含基本項、聯集運算子和遞迴項。 基本項會執行遞迴聯集作業的第一個疊代。遞迴項會執行其餘的疊代,且必須包含對遞迴 CTE 的一個自我參照。只有遞迴項可以包含自我參照。
在上述範例中,遞迴 CTE 包含下列元件:
- 遞迴 CTE 名稱:
CTE_1 - 基本期限:
SELECT 1 AS iteration - 聯集運算子:
UNION ALL - 遞迴項:
SELECT iteration + 1 AS iteration FROM CTE_1 WHERE iteration < 3
如要進一步瞭解遞迴 CTE 語法、規則和範例,請參閱 GoogleSQL 參考文件中的WITH子句。
探索有向無環圖 (DAG) 中的可達性
您可以使用遞迴查詢,探索有向無環圖 (DAG) 中的可連性。下列查詢會找出圖表 (稱為 GraphData) 中可從節點 5 抵達的所有節點:
WITH RECURSIVE
GraphData AS (
-- 1 5
-- / \ / \
-- 2 - 3 6 7
-- | \ /
-- 4 8
SELECT 1 AS from_node, 2 AS to_node UNION ALL
SELECT 1, 3 UNION ALL
SELECT 2, 3 UNION ALL
SELECT 3, 4 UNION ALL
SELECT 5, 6 UNION ALL
SELECT 5, 7 UNION ALL
SELECT 6, 8 UNION ALL
SELECT 7, 8
),
R AS (
(SELECT 5 AS node)
UNION ALL
(
SELECT GraphData.to_node AS node
FROM R
INNER JOIN GraphData
ON (R.node = GraphData.from_node)
)
)
SELECT DISTINCT node FROM R ORDER BY node;
上述範例會產生下列結果:
/*------+
| node |
+------+
| 5 |
| 6 |
| 7 |
| 8 |
+------*/
排解疊代限制錯誤
遞迴 CTE 可能會導致無限遞迴,也就是遞迴項持續執行,但未達到終止條件。為終止無限遞迴,系統會對每個遞迴 CTE 強制執行疊代次數限制。如果是 BigQuery,反覆運算次數上限為 500 次。遞迴 CTE 達到疊代次數上限後,CTE 執行作業就會因錯誤而中止。
由於遞迴 CTE 的運算成本可能很高,因此設下這項限制。如果 CTE 的疊代次數過多,就會耗用大量系統資源,且完成時間會大幅延長。
達到疊代次數上限的查詢通常缺少適當的終止條件,因此會建立無限迴圈,或是在不適當的情況下使用遞迴 CTE。
如果遇到遞迴疊代限制錯誤,請參閱本節的建議。
檢查是否有無限遞迴
為避免無限遞迴,請確保遞迴項在執行一定次數的疊代後,能夠產生空白結果。
如要檢查無限遞迴,方法之一是將遞迴 CTE 轉換為含有前 100 次疊代的 REPEAT 迴圈,如下所示:TEMP TABLE
DECLARE current_iteration INT64 DEFAULT 0; CREATE TEMP TABLE recursive_cte_name AS SELECT base_expression, current_iteration AS iteration; REPEAT SET current_iteration = current_iteration + 1; INSERT INTO recursive_cte_name SELECT recursive_expression, current_iteration FROM recursive_cte_name WHERE termination_condition_expression AND iteration = current_iteration - 1 AND current_iteration < 100; UNTIL NOT EXISTS(SELECT * FROM recursive_cte_name WHERE iteration = current_iteration) END REPEAT;
替換下列值:
recursive_cte_name:要偵錯的遞迴 CTE。base_expression:遞迴 CTE 的基本條件。recursive_expression:遞迴 CTE 的遞迴項。termination_condition_expression:遞迴 CTE 的終止運算式。
舉例來說,請看以下名為 TestCTE 的遞迴 CTE:
WITH RECURSIVE
TestCTE AS (
SELECT 1 AS n
UNION ALL
SELECT n + 3 FROM TestCTE WHERE MOD(n, 6) != 0
)
這個範例使用下列值:
recursive_cte_name:TestCTEbase_expression:SELECT 1recursive_expression:n + 3termination_condition_expression:MOD(n, 6) != 0
因此,下列程式碼會測試 TestCTE 是否出現無限遞迴:
DECLARE current_iteration INT64 DEFAULT 0; CREATE TEMP TABLE TestCTE AS SELECT 1 AS n, current_iteration AS iteration; REPEAT SET current_iteration = current_iteration + 1; INSERT INTO TestCTE SELECT n + 3, current_iteration FROM TestCTE WHERE MOD(n, 6) != 0 AND iteration = current_iteration - 1 AND current_iteration < 10; UNTIL NOT EXISTS(SELECT * FROM TestCTE WHERE iteration = current_iteration) END REPEAT; -- Print the number of rows produced by each iteration SELECT iteration, COUNT(1) AS num_rows FROM TestCTE GROUP BY iteration ORDER BY iteration; -- Examine the actual result produced for a specific iteration SELECT * FROM TestCTE WHERE iteration = 2;
上述範例會產生下列結果,其中包含疊代 ID 和該疊代期間產生的資料列數:
/*-----------+----------+
| iteration | num_rows |
+-----------+----------+
| 0 | 1 |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 7 | 1 |
| 8 | 1 |
| 9 | 1 |
| 10 | 1 |
+-----------+----------*/
以下是疊代 2 期間產生的實際結果:
/*----------+-----------+
| n | iteration |
+----------+-----------+
| 7 | 2 |
+----------+-----------*/
如果資料列數一律大於零 (本範例即為如此),則樣本很可能出現無限遞迴。
確認遞迴 CTE 的適當用法
確認您在適當情境中使用遞迴 CTE。
遞迴 CTE 的設計目的是查詢階層式資料和圖形資料,因此運算成本可能很高。如果不是查詢這兩種資料,請考慮其他做法,例如使用 LOOP 陳述式搭配非遞迴 CTE。
將遞迴 CTE 分割為多個遞迴 CTE
如果遞迴 CTE 需要的疊代次數超過上限,或許可以將遞迴 CTE 分解為多個遞迴 CTE。
您可以透過類似下列的查詢結構,分割遞迴 CTE:
WITH RECURSIVE CTE_1 AS ( SELECT base_expression UNION ALL SELECT recursive_expression FROM CTE_1 WHERE iteration < 500 ), CTE_2 AS ( SELECT * FROM CTE_1 WHERE iteration = 500 UNION ALL SELECT recursive_expression FROM CTE_2 WHERE iteration < 500 * 2 ), CTE_3 AS ( SELECT * FROM CTE_2 WHERE iteration = 500 * 2 UNION ALL SELECT recursive_expression FROM CTE_3 WHERE iteration < 500 * 3 ), [, ...] SELECT * FROM CTE_1 UNION ALL SELECT * FROM CTE_2 WHERE iteration > 500 UNION ALL SELECT * FROM CTE_3 WHERE iteration > 500 * 2 [...]
替換下列值:
base_expression:目前 CTE 的基本字詞運算式。recursive_expression:目前 CTE 的遞迴項運算式。
舉例來說,下列程式碼會將 CTE 分成三個不同的 CTE:
WITH RECURSIVE
CTE_1 AS (
SELECT 1 AS iteration
UNION ALL
SELECT iteration + 1 AS iteration FROM CTE_1 WHERE iteration < 10
),
CTE_2 AS (
SELECT * FROM CTE_1 WHERE iteration = 10
UNION ALL
SELECT iteration + 1 AS iteration FROM CTE_2 WHERE iteration < 10 * 2
),
CTE_3 AS (
SELECT * FROM CTE_2 WHERE iteration = 10 * 2
UNION ALL
SELECT iteration + 1 AS iteration FROM CTE_3 WHERE iteration < 10 * 3
)
SELECT iteration FROM CTE_1
UNION ALL
SELECT iteration FROM CTE_2 WHERE iteration > 10
UNION ALL
SELECT iteration FROM CTE_3 WHERE iteration > 20
ORDER BY 1 ASC
在上述範例中,500 次疊代會替換為 10 次疊代,這樣就能更快查看查詢結果。這項查詢會產生 30 個資料列,但每個遞迴 CTE 只會疊代 10 次。輸出內容如下所示:
/*-----------+
| iteration |
+-----------+
| 2 |
| ... |
| 30 |
+-----------*/
您可以在更大的疊代中測試先前的查詢。
使用迴圈,而非遞迴 CTE
為避免達到疊代次數上限,請考慮使用迴圈,而非遞迴 CTE。
您可以使用多種迴圈陳述式建立迴圈,例如 LOOP、REPEAT 或 WHILE。詳情請參閱「迴圈」。
變更遞迴限制
如果您認為適用下列因素,請與客戶服務團隊聯絡,要求提高遞迴限制:
- 遞迴 CTE 有充分理由執行超過 500 次疊代。
- 您可接受執行時間較長。
請注意,提高遞迴限制可能會有以下風險:
- CTE 可能會失敗,並顯示其他錯誤訊息,例如超出記憶體或逾時。
- 如果專案採用即付即用價格模式,您可能仍會收到計費層級錯誤,直到改用以容量為準的價格模式為止。
- 如果遞迴 CTE 的疊代次數過多,就會耗用大量資源。在相同預訂中執行的其他查詢會共用資源,因此可能會受到影響。
定價
如果您使用以量計價,BigQuery 會根據執行遞迴 CTE 查詢時處理的位元組數收費。
詳情請參閱「查詢大小計算」。
配額
如要瞭解遞迴 CTE 配額和限制,請參閱「配額與限制」。