閱讀331 返回首頁    go 技術社區[雲棲]


PostgreSQL 10.0 preview 功能增強 - BRIN 索引更新smooth化

標簽

PostgreSQL , 10.0 , BRIN , de-summarization , summarization , 平滑更新BRIN , 平滑失效BRIN


背景

我們將數據存入PostgreSQL時,如果創建的是堆表,那麼數據是往數據文件的末尾不斷追加存儲的。

為了提高數據的檢索速度,可以對響應的字段創建索引,在PostgreSQL中,已有8種索引類型,分別是B-Tree,hash, gin, gist, sp-gist, brin, bloom, rum。分別對應不同的應用場景。

如果數據值與物理存儲線性相關性比較好,可以使用塊級索引(BRIN),以塊(或連續的若幹塊)為最小單位,索引中存儲的是這些最小單位的統計信息(最大值,最小值,記錄條數,SUM,NULL值條數等)。

為了提高插入速度,HEAP末端的塊,可能並不會實時的更新到BRIN索引中,10.0以前,vacuum或者autovacuum表時,會生成未生成統計信息的HEAP block range,如果插入很快,比如在一個vacuum周期內,插入了100個數據塊的內容,那麼vacuum需要掃描這100個數據塊並生成BRIN索引對應的信息。

pic

10.0 寫時觸發更新brin

為了防止插入過快,導致vacuum一次要統計過多的數據塊,或者導致未進入BRIN索引的堆表末端數據塊過多,10.0的改進如下,在插入時,如果插入到下一個block range的塊時,自動觸發vacuum去統計前一個block range的BRIN統計信息(如果還沒有被統計的話)。

這樣就可以解決前麵提到的問題,因為insert的時候,隻要到達block range邊界,就會自動觸發vacuum去統計它。

開啟"insert的時候,隻要到達block range邊界,就會自動觸發vacuum去統計它"的方法,創建索引時,指定autosummarize參數。

https://www.postgresql.org/docs/devel/static/sql-createindex.html

BRIN indexes accept different parameters:  
  
pages_per_range  
Defines the number of table blocks that make up one block range for each entry of a BRIN index (see Section 65.1 for more details). The default is 128.  
  
autosummarize  
Defines whether a summarization run is invoked for the previous page range whenever an insertion is detected on the next one.  
  
create index idx on table using brin (id) with (autosummarize=on);  

pic

同時,10.0還新增了用戶UDF接口,用戶可以自己調用函數,去統計(更新)BRIN索引,指定表,以及堆表對應的block_id即可。

+-- Test brin_summarize_range  
+CREATE TABLE brin_summarize (  
+    value int  
+) WITH (fillfactor=10, autovacuum_enabled=false);  
+CREATE INDEX brin_summarize_idx ON brin_summarize USING brin (value) WITH (pages_per_range=2);  
+-- Fill a few pages  
+DO $$  
+DECLARE curtid tid;  
+BEGIN  
+  LOOP  
+    INSERT INTO brin_summarize VALUES (1) RETURNING ctid INTO curtid;  
+    EXIT WHEN curtid > tid '(2, 0)';  
+  END LOOP;  
+END;  
+$$;  
+-- summarize one range  
+SELECT brin_summarize_range('brin_summarize_idx', 0);  
+ brin_summarize_range   
+----------------------  
+                    1  
+(1 row)  
+  
+-- nothing: already summarized  
+SELECT brin_summarize_range('brin_summarize_idx', 1);  
+ brin_summarize_range   
+----------------------  
+                    0  
+(1 row)  
+  
+-- summarize one range  
+SELECT brin_summarize_range('brin_summarize_idx', 2);  
+ brin_summarize_range   
+----------------------  
+                    1  
+(1 row)  
+  
+-- nothing: page doesn't exist in table  
+SELECT brin_summarize_range('brin_summarize_idx', 4294967295);  
+ brin_summarize_range   
+----------------------  
+                    0  
+(1 row)  
+  
+-- invalid block number values  
+SELECT brin_summarize_range('brin_summarize_idx', -1);  
+ERROR:  block number out of range: -1  
+SELECT brin_summarize_range('brin_summarize_idx', 4294967296);  
+ERROR:  block number out of range: 4294967296  

patch信息如下

BRIN auto-summarization  
  
Previously, only VACUUM would cause a page range to get initially  
summarized by BRIN indexes, which for some use cases takes too much time  
since the inserts occur.  To avoid the delay, have brininsert request a  
summarization run for the previous range as soon as the first tuple is  
inserted into the first page of the next range.  Autovacuum is in charge  
of processing these requests, after doing all the regular vacuuming/  
analyzing work on tables.  
  
This doesn't impose any new tasks on autovacuum, because autovacuum was  
already in charge of doing summarizations.  The only actual effect is to  
change the timing, i.e. that it occurs earlier.  For this reason, we  
don't go any great lengths to record these requests very robustly; if  
they are lost because of a server crash or restart, they will happen at  
a later time anyway.  
  
Most of the new code here is in autovacuum, which can now be told about  
"work items" to process.  This can be used for other things such as GIN  
pending list cleaning, perhaps visibility map bit setting, both of which  
are currently invoked during vacuum, but do not really depend on vacuum  
taking place.  
  
The requests are at the page range level, a granularity for which we did  
not have SQL-level access; we only had index-level summarization  
requests via brin_summarize_new_values().  It seems reasonable to add  
SQL-level access to range-level summarization too, so add a function  
brin_summarize_range() to do that.  
  
Authors: Álvaro Herrera, based on sketch from Simon Riggs.  
Reviewed-by: Thomas Munro.  
Discussion: https://postgr.es/m/20170301045823.vneqdqkmsd4as4ds@alvherre.pgsql  

10.0 brin索引條目失效接口

brin記錄的是block range的最大值,最小值,隨著對應block range內數據的更新,刪除,BRIN IDX中對應的block range統計信息可能會越來越寬泛(不準確),因此為了提高BRIN的精度,10.0新增了一個失效接口,可以將對應block range的brin index內的條目失效,然後你可以等VACUUM再次統計它,或者調用前麵提到的UDF接口來統計它。

pic

失效heap block range對應brin idx條目的方法

+SELECT brin_desummarize_range('brinidx', 0);  
+ brin_desummarize_range   
+------------------------  
+   
+(1 row)  
+  
  
+-- Tests for brin_desummarize_range  
+SELECT brin_desummarize_range('brinidx', -1); -- error, invalid range  
+ERROR:  block number out of range: -1  
+SELECT brin_desummarize_range('brinidx', 0);  
+ brin_desummarize_range   
+------------------------  
+   
+(1 row)  
+  
+SELECT brin_desummarize_range('brinidx', 0);  
+ brin_desummarize_range   
+------------------------  
+   
+(1 row)  
+  
+SELECT brin_desummarize_range('brinidx', 100000000);  
+ brin_desummarize_range   
+------------------------  
+   
+(1 row)  
+  

patch信息如下

BRIN de-summarization  
  
When the BRIN summary tuple for a page range becomes too "wide" for the  
values actually stored in the table (because the tuples that were  
present originally are no longer present due to updates or deletes), it  
can be useful to remove the outdated summary tuple, so that a future  
summarization can install a tighter summary.  
  
This commit introduces a SQL-callable interface to do so.  
  
Author: Álvaro Herrera  
Reviewed-by: Eiji Seki  
Discussion: https://postgr.es/m/20170228045643.n2ri74ara4fhhfxf@alvherre.pgsql  

這個patch的討論,詳見郵件組,本文末尾URL。

PostgreSQL社區的作風非常嚴謹,一個patch可能在郵件組中討論幾個月甚至幾年,根據大家的意見反複的修正,patch合並到master已經非常成熟,所以PostgreSQL的穩定性也是遠近聞名的。

參考

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=7526e10224f0792201e99631567bbe44492bbde4

https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=c655899ba9ae2a0d24e99c797167c33e0cfa0820

https://www.postgresql.org/docs/devel/static/sql-createindex.html

最後更新:2017-04-07 21:25:10

  上一篇:go Gradle技巧係列一: 打印Task輸入輸出等信息
  下一篇:go PostgreSQL 10.0 preview 變化 - 邏輯複製pg_hba.conf變化,不再使用replication條目