Azure Cosmos DB for PostgreSQL 中的資料表共置

適用於: Azure Cosmos DB for PostgreSQL (由 PostgreSQL 的超大規模 (Citus) 資料庫延伸模組提供)

共置表示將相關資訊一起儲存在相同的節點上。 當不需要任何網路流量,即可存取所有必要資料時,查詢便可快速執行。 在不同的節點上共置相關資料,可讓查詢在每個節點上有效率地平行執行。

雜湊分散式資料表的資料共置

在 Azure Cosmos DB for PostgreSQL 中,如果散發資料行中的值雜湊落在分區的雜湊範圍內,資料列就會儲存在分區中。 具有相同雜湊範圍的分區一律放在相同的節點上。 具有相等散發資料行值的資料列一律位於跨資料表的相同節點上。 雜湊分散式資料表的概念也稱為資料列型分區化。 在結構描述型分區化中,分散式結構描述內的資料表一律會共置。

Diagram shows shards with the same hash range placed on the same node for events shards and page shards.

實際的共置範例

請考慮下列可能屬於多租用戶 Web 分析 SaaS 的資料表:

CREATE TABLE event (
  tenant_id int,
  event_id bigint,
  page_id int,
  payload jsonb,
  primary key (tenant_id, event_id)
);

CREATE TABLE page (
  tenant_id int,
  page_id int,
  path text,
  primary key (tenant_id, page_id)
);

現在我們想要回答客戶面向儀表板可能發出的查詢。 範例查詢是「針對租用戶六中以 '/blog' 開頭的所有頁面,傳回過去一週的造訪次數。」

如果我們的資料位於單一 PostgreSQL 伺服器中,我們可以輕鬆地使用 SQL 所提供的豐富關聯式作業集來表達查詢:

SELECT page_id, count(event_id)
FROM
  page
LEFT JOIN  (
  SELECT * FROM event
  WHERE (payload->>'time')::timestamptz >= now() - interval '1 week'
) recent
USING (tenant_id, page_id)
WHERE tenant_id = 6 AND path LIKE '/blog%'
GROUP BY page_id;

只要此查詢的工作集可放入記憶體中,單一伺服器資料表就是適當的解決方案。 讓我們考慮使用 Azure Cosmos DB for PostgreSQL 調整資料模型的機會。

依識別碼散發資料表

單一伺服器查詢會隨著租用戶數目和每個租用戶儲存的資料成長而開始變慢。 工作集會停止放入記憶體中,而且 CPU 會變成瓶頸。

在此情況下,我們可以使用 Azure Cosmos DB for PostgreSQL,跨多個節點將資料分區。 決定分區時,我們需要做出的第一個且最重要選擇是散發資料行。 讓我們從針對事件資料表使用 event_id,以及針對 page 資料表使用 page_id 的幼稚選擇開始:

-- naively use event_id and page_id as distribution columns

SELECT create_distributed_table('event', 'event_id');
SELECT create_distributed_table('page', 'page_id');

當資料分散到不同的背景工作角色時,我們無法像在單一 PostgreSQL 節點上一樣執行聯結。 相反地,我們需要發出兩個查詢:

-- (Q1) get the relevant page_ids
SELECT page_id FROM page WHERE path LIKE '/blog%' AND tenant_id = 6;

-- (Q2) get the counts
SELECT page_id, count(*) AS count
FROM event
WHERE page_id IN (/*…page IDs from first query…*/)
  AND tenant_id = 6
  AND (payload->>'time')::date >= now() - interval '1 week'
GROUP BY page_id ORDER BY count DESC LIMIT 10;

之後,應用程式必須合併來自這兩個步驟的結果。

執行查詢必須在分散於節點的分區中查閱資料。

Diagram shows an inefficient approach that uses multiple queries against the event and page tables in two nodes.

在此情況下,資料散發會產生重大缺點:

  • 查詢每個分區和執行多個查詢的額外負荷。
  • Q1 將許多資料列傳回給用戶端的額外負荷。
  • Q2 變得很大。
  • 若需要以多個步驟撰寫查詢,則應用程式需要變更。

資料是分散的,因此可以平行處理查詢。 只有在查詢所執行的工作量遠大於查詢許多分區的額外負荷時,才有益處。

依租用戶散發資料表

在 Azure Cosmos DB for PostgreSQL 中,具有相同散發資料行值的資料列保證位於相同的節點上。 從頭開始,我們可以使用 tenant_id 作為散發資料行來建立資料表。

-- co-locate tables by using a common distribution column
SELECT create_distributed_table('event', 'tenant_id');
SELECT create_distributed_table('page', 'tenant_id', colocate_with => 'event');

現在 Azure Cosmos DB for PostgreSQL 可以回答原始的單一伺服器查詢,而不需修改 (Q1):

SELECT page_id, count(event_id)
FROM
  page
LEFT JOIN  (
  SELECT * FROM event
  WHERE (payload->>'time')::timestamptz >= now() - interval '1 week'
) recent
USING (tenant_id, page_id)
WHERE tenant_id = 6 AND path LIKE '/blog%'
GROUP BY page_id;

由於 tenant_id 上的篩選和聯結,Azure Cosmos DB for PostgreSQL 知道可以使用共置分區集來回答整個查詢,而這些共置分區包含該特定租用戶的資料。 單一 PostgreSQL 節點可以採取單一步驟回答查詢。

Diagram shows a single query to one node, which is a more efficient approach.

在某些情況下,必須變更查詢和資料表結構描述,以在唯一的條件約束和聯結條件中包含租用戶識別碼。 此變更通常很簡單。

下一步