Citus 分布式 PostgreSQL 集群 - SQL Reference(SQL支持和變通方案)
由于 Citus 通過擴(kuò)展 PostgreSQL 提供分布式功能,因此它與 PostgreSQL 結(jié)構(gòu)兼容。這意味著用戶可以使用豐富且可擴(kuò)展的 PostgreSQL 生態(tài)系統(tǒng)附帶的工具和功能來處理使用 Citus 創(chuàng)建的分布式表。
Citus 對(duì)它能夠在單個(gè)工作節(jié)點(diǎn)上執(zhí)行的任何查詢具有 100% 的 SQL 覆蓋率。在訪問有關(guān)單個(gè)租戶的信息時(shí),此類查詢?cè)诙嘧鈶魬?yīng)用程序中很常見。
- https://docs.citusdata.com/en/v11.0-beta/use_cases/multi_tenant.html#mt-use-case
甚至跨節(jié)點(diǎn)查詢(用于并行計(jì)算)也支持大多數(shù) SQL 功能。但是,組合來自多個(gè)節(jié)點(diǎn)的信息的查詢不支持某些 SQL 功能。
跨節(jié)點(diǎn) SQL 查詢的限制:
- SELECT … FOR UPDATE 僅適用于單分片查詢
https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE
- TABLESAMPLE 僅適用于單分片查詢
https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FROM
- 關(guān)聯(lián)子查詢僅當(dāng)關(guān)聯(lián)在分布列上時(shí)才受支持。
https://docs.citusdata.com/en/v11.0-beta/get_started/concepts.html#dist-column
- 分布式表之間的外連接僅在分布列上受支持。
https://docs.citusdata.com/en/v11.0-beta/get_started/concepts.html#dist-column
- 僅當(dāng)分布式表在外側(cè)時(shí),才支持分布式表和引用表或本地表之間的外連接
- 遞歸 CTE 僅適用于單分片查詢
https://www.postgresql.org/docs/current/static/queries-with.html#idm46428713247840
- 分組集僅適用于單分片查詢
https://www.postgresql.org/docs/current/static/queries-table-expressions.html#QUERIES-GROUPING-SETS
要了解有關(guān) PostgreSQL 及其功能的更多信息,您可以訪問 PostgreSQL 文檔。有關(guān) PostgreSQL SQL 命令方言(可供 Citus 用戶按原樣使用)的詳細(xì)參考,您可以查看 SQL 命令參考。
http://www.postgresql.org/docs/current/static/index.html
http://www.postgresql.org/docs/current/static/sql-commands.html
變通方案
在嘗試變通方案之前,請(qǐng)考慮 Citus 是否適合您的情況。Citus 當(dāng)前版本適用于實(shí)時(shí)分析和多租戶用例。
- https://docs.citusdata.com/en/v11.0-beta/get_started/what_is_citus.html#when-to-use-citus
Citus 支持多租戶用例中的所有 SQL 語句。即使在跨節(jié)點(diǎn)查詢的實(shí)時(shí)分析用例中,Citus 也支持大多數(shù)語句。 Citus 不支持的 PostgreSQL 特性中列出了幾種不受支持的查詢類型? 許多不受支持的功能都有變通方案;以下是一些最有用的。
- https://docs.citusdata.com/en/v11.0-beta/faq/faq.html#unsupported
使用 CTE 解決限制
當(dāng) SQL 查詢不受支持時(shí),解決它的一種方法是使用 CTE,它使用我們所謂的 pull-push 執(zhí)行。
SELECT * FROM ref LEFT JOIN dist USING (id) WHERE dist.value > 10;
/*
ERROR: cannot pushdown the subquery
DETAIL: There exist a reference table in the outer part of the outer join
*/
要解決此限制,您可以通過將分布式部分包裝在 CTE 中來將查詢轉(zhuǎn)換為路由器查詢
WITH x AS (SELECT * FROM dist WHERE dist.value > 10)
SELECT * FROM ref LEFT JOIN x USING (id);
請(qǐng)記住,coordinator 會(huì)將 CTE 的結(jié)果發(fā)送給所有需要它進(jìn)行處理的 worker。因此,最好將最具體的過濾器和限制添加到內(nèi)部查詢中,或者聚合表。這減少了此類查詢可能導(dǎo)致的網(wǎng)絡(luò)開銷。在子查詢/CTE 網(wǎng)絡(luò)開銷中了解更多信息。
- https://docs.citusdata.com/en/v11.0-beta/performance/performance_tuning.html#subquery-perf
臨時(shí)表:不得已的解決方法
即使通過子查詢使用推拉執(zhí)行,仍有一些查詢不受支持。其中之一是在分布式表上使用分組集。
https://docs.citusdata.com/en/v11.0-beta/faq/faq.html#unsupported
https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-GROUPING-SETS
在我們的實(shí)時(shí)分析教程中,我們創(chuàng)建了一個(gè)名為 github_events 的表,由 user_id 列分布。讓我們查詢它并找到一組預(yù)選的 repos 的最早事件,按事件類型和事件公開的組合分組。一種方便的方法是使用分組集。但是,如前所述,分布式查詢尚不支持此功能:
https://docs.citusdata.com/en/v11.0-beta/get_started/tutorial_realtime_analytics.html#real-time-analytics-tutorial
-- this won't work
SELECT repo_id, event_type, event_public,
grouping(event_type, event_public),
min(created_at)
FROM github_events
WHERE repo_id IN (8514, 15435, 19438, 21692)
GROUP BY repo_id, ROLLUP(event_type, event_public);
ERROR: could not run distributed query with GROUPING
HINT: Consider using an equality filter on the distributed table's partition column.
不過,有一個(gè)竅門。我們可以將相關(guān)信息作為臨時(shí)表拉取到 coordinator:
-- grab the data, minus the aggregate, into a local table
CREATE TEMP TABLE results AS (
SELECT repo_id, event_type, event_public, created_at
FROM github_events
WHERE repo_id IN (8514, 15435, 19438, 21692)
);
-- now run the aggregate locally
SELECT repo_id, event_type, event_public,
grouping(event_type, event_public),
min(created_at)
FROM results
GROUP BY repo_id, ROLLUP(event_type, event_public);
repo_id | event_type | event_public | grouping | min
---------+-------------------+--------------+----------+---------------------
8514 | PullRequestEvent | t | 0 | 2016-12-01 05:32:54
8514 | IssueCommentEvent | t | 0 | 2016-12-01 05:32:57
19438 | IssueCommentEvent | t | 0 | 2016-12-01 05:48:56
21692 | WatchEvent | t | 0 | 2016-12-01 06:01:23
15435 | WatchEvent | t | 0 | 2016-12-01 05:40:24
21692 | WatchEvent | | 1 | 2016-12-01 06:01:23
15435 | WatchEvent | | 1 | 2016-12-01 05:40:24
8514 | PullRequestEvent | | 1 | 2016-12-01 05:32:54
8514 | IssueCommentEvent | | 1 | 2016-12-01 05:32:57
19438 | IssueCommentEvent | | 1 | 2016-12-01 05:48:56
15435 | | | 3 | 2016-12-01 05:40:24
21692 | | | 3 | 2016-12-01 06:01:23
19438 | | | 3 | 2016-12-01 05:48:56
8514 | | | 3 | 2016-12-01 05:32:54
在 coordinator 上創(chuàng)建臨時(shí)表是最后的手段。它受節(jié)點(diǎn)的磁盤大小和 CPU 的限制。