2015-09-26 74 views
2

我的軟件每30分鐘運行一次cronjob,它會從Google Analytics/Social網絡中提取數據並將結果插入Postgres數據庫。Postgres分區?

的數據是這樣的:

url text NOT NULL,  
rangeStart timestamp NOT NULL, 
rangeEnd timestamp NOT NULL, 
createdAt timestamp DEFAULT now() NOT NULL, 
... 
(various integer columns) 

由於一個查詢返回的10個000多個項目,這顯然不是存儲在一個表中這個數據是個好主意。以這個速度,cronjob每天將產生大約48萬條記錄,每個月大約有1450萬條記錄。

我認爲,解決辦法是使用多個表,例如我可以用一個特定的表存儲在一個給定月份生成的數據:stats_2015_09,stats_2015_10,stats_2015_11等

我知道Postgres的支持表分區。不過,我對這個概念並不熟悉,所以我不確定最好的辦法是什麼。在這種情況下,我需要分區嗎?還是應該手動創建這些表?或者也許有更好的解決方案?

稍後將以各種方式查詢數據,並且這些查詢預計將運行得很快。

編輯:

如果我最終12-14表,每個存儲10-20百萬行,Postgres的應該仍然能夠快速運行SELECT語句,對不對?插入不一定要超快。

+1

關於此主題的[官方文檔](http://www.postgresql.org/docs/9.4/static/ddl-partitioning.html)精闢,應該足夠。 – klin

+0

參見[pg_partman](http://pgxn.org/dist/pg_partman/doc/pg_partman.html),這是一個易於使用的擴展,提供了內置管道缺少的許多細節。 – IMSoP

回答

5

這太長了評論。

分區在各種情況下都是一個好主意。兩個想到的是:

  • 您的查詢有一個WHERE子句,可以很容易地映射到一個或幾個分區。
  • 您想快速刪除歷史數據(刪除分區比刪除記錄快)。

不知道要運行的查詢類型,很難說分區是否是一個好主意。

我想我可以說,數據分割成不同的表是主意,因爲它是一個維護的噩夢:

  • 你不能有外鍵引用到表中。
  • 跨越多個表的查詢非常麻煩,所以很簡單的問題很難回答。
  • 維護表成爲一場噩夢(添加/刪除列)。
  • 如果您擁有不同角色的用戶,則必須謹慎維護權限。

無論如何,開始的地方是Postgres關於分區的文檔,它是here。我應該注意到Postgres的實現比其他數據庫更笨拙,因此您可能需要查看MySQL或SQL Server的文檔以瞭解它正在做什麼。

+0

感謝您的回覆。我無法確切地告訴我們需要哪些查詢,因爲歷史數據將由另一個應用查詢。但我認爲最重要的關鍵是日期範圍(從 - 到),因此基於此創建分區也許是個好主意。 – user2297996

1

首先,我想挑戰你的問題的前提是:

由於一個查詢返回的10個000多個項目,這顯然不是存儲在一個表中這個數據是個好主意。

據我所知,沒有根本的原因,爲什麼數據庫不能很好地處理數百萬行的單個表。在極端情況下,如果您創建了一個沒有索引的表格,並且只需將行添加到它,Postgres就可以繼續將這些行寫入磁盤,直到您耗盡存儲空間。 (可能還有其他的限制內,我不知道。但即便如此,他們)當您嘗試做一些與數據

的問題只來了,確切的問題 - 因此確切的解決方案 - 取決於你做什麼

如果要定期刪除其是不是一個固定的時間表前插入更多的所有行,你可以在createdAt列分區的數據。然後DELETE將變成非常高效的DROP TABLE,並且所有INSERT將通過觸發器路由到「當前」分區(或者如果您的導入腳本知道分區命名方案,甚至可以繞過它)。但是,SELECT s可能無法在其WHERE子句中指定範圍createAt值,因此需要查詢所有分區併合並結果。您一次保留的分區越多,效率就越低。

或者,您可以檢查表上的工作負載,並查看所有查詢已經或很容易明確指出rangeStart值。在這種情況下,您可以在rangeStart上進行分區,並且在規劃每個SELECT查詢時,查詢計劃程序將能夠消除除一個或幾個分區以外的所有分區。 INSERT需要通過觸發器路由到適當的表,並且維護操作(例如刪除不再需要的舊數據)效率會低得多。

或者,也許你知道,一旦rangeEnd變得「太舊」你將不再需要的數據,並能得到兩個好處:通過rangeEnd分區,確保所有SELECT查詢明確提到rangeEnd,幷包含你的數據下降分區不再感興趣

爲了從git借用Linus Torvald的術語,分區的「管道」以表繼承的形式構建到Postgres中,但是除了示例以外,「瓷器」的用法很少在手冊中。但是,有一個很好的extension called pg_partman,它提供了基於ID或日期範圍管理分區集的功能;閱讀文檔以瞭解不同的操作模式是非常值得的。在我的情況下,沒有任何匹配,但是分叉​​比從零開始寫所有事情要容易得多。

請記住,分區並不是免費的,並且如果根據上述考慮因素沒有明顯的列分區候選者,那麼實際上最好將數據留在一個表中,並考慮其他優化策略。例如,部分索引(CREATE INDEX ... WHERE)可能能夠處理最常查詢的行子集;也許與「覆蓋索引」相結合,其中Postgres可以直接從索引返回查詢結果而不參考主表結構(「僅索引掃描」)。

+0

感謝您的詳細解釋,這非常有用!我已經檢查過這些文檔,現在會檢查pg_partman。 到目前爲止,created似乎是一個很好的專欄來分區。我研究了查詢代碼,最重要的查詢可以明確提及它(作爲範圍)。 – user2297996

+0

關於將數據保存在一張表中:這是一個選項。但即使該表正確索引,如果有5億行,那麼SELECT也會相對較慢,除非索引以某種方式確保只在每個查詢中檢查一小部分數據集。因此,使用分區或其他技術來分割數據似乎是一種更好的方法。我錯了嗎? – user2297996

+0

@ user2297996「,除非索引以某種方式保證只有一小部分數據集必須在每個查詢上進行檢查」 - 這與索引非常類似,可以高效地跳到數據集的右側部分。我不知道* how * btree索引的工作細節,但根據我對數據庫的經驗法則,如果我不知道它是如何工作的,那麼DBMS可能會做出比我更好的決策試圖通過手工優化低級結構。 – IMSoP