Postgresql

為什麼 PostgreSQL FDW 為這個點查詢與多個後端伺服器通信?

  • July 8, 2019

我已經使用下表設置了一個 PostgreSQL FDW 伺服器,由user_id四個以上的伺服器分片:

CREATE TABLE my_big_table
(
   user_id bigint NOT NULL,
   serial bigint NOT NULL,         -- external, incrementing only
   some_object_id bigint NOT NULL,
   timestamp_ns bigint NOT NULL,
   object_type smallint NOT NULL,
   other_type smallint NOT NULL,
   data bytea
) PARTITION BY LIST (mod(user_id, 4)) ;
CREATE SERVER shardA
   FOREIGN DATA WRAPPER postgres_fdw
   OPTIONS (host '192.168.200.11', port '5432', dbname 'postgres', fetch_size '10000');
.
.
.
CREATE SERVER shardD
   FOREIGN DATA WRAPPER postgres_fdw
   OPTIONS (host '192.168.200.14', port '5432', dbname 'postgres', fetch_size '10000');
create foreign table my_big_table_mod4_s0 partition of my_big_table
   for values in (0) server shardA
   OPTIONS (table_name 'my_big_table_mod4_s0');
.
.
.
create foreign table my_big_table_mod4_s3 partition of my_big_table
   for values in (3) server shardD
   OPTIONS (table_name 'my_big_table_mod4_s3');

給定一個單一的查詢user_id,我希望 FDW 基於簡單的分區修剪選擇一個後端,但explain顯示對所有四台伺服器的外部表掃描……我如何提示 FDW 更聰明?

PostgreSQL 缺乏對它需要聲明的“mod”函式的洞察力,這user_id=97也意味著mod(user_id,4)=1. 如果您手動提供該見解,它可能會尊重它:

WHERE user_id=$1 and mod(user_id,4)=mod($1,4)

這與FDW無關。如果所有分區/表都是本地的,那麼答案將保持不變。

您可以使用雜湊分區,然後它會自動生成洞察力。

這是由於在父表上的列表分區中使用了表達式,並且 PosgreSQL 只能對列表分區中的簡單相等檢查執行修剪,如文件中所述

保持分區約束簡單,否則規劃器可能無法證明可能不需要訪問子表。對列表分區使用簡單的相等條件,或者對范圍分區使用簡單的範圍測試,如前面的範例所示。一個好的經驗法則是分區約束應該只包含分區列與使用 B-tree-indexable 運算符的常量的比較,因為分區鍵中只允許 B-tree-indexable 列。

為了解決這個問題,這裡有一個想法:而不是PARTITION BY LIST (mod(user_id, 4)), dopartition by hash(user_id)然後在分區上:FOR VALUES WITH (MODULUS 4, REMAINDER 0) server shardA.

然後,PostgreSQL FDW 將按預期實際修剪分區。

但是,數據不會按值的實際模數分佈user_id,而是基於值的散列的模數。由於各種原因(例如,已經以非散列方式分發的 TB 級數據),這可能是不可接受的。

引用自:https://dba.stackexchange.com/questions/242368