Postgresql

PostgreSQL中的漸進式子表掃描?

  • May 8, 2019

我們有一個僅附加events表,其中正在收集來自不同設備的事件。

我們使用 PostgreSQL 9.6 和pg_partman將表拆分為每月分區。使用列

對數據進行分區。 每個月表有大約 100M 行。 event_time

應用程序端有一個查詢,用於顯示設備的最新事件。它看起來像這樣(簡化):

SELECT event_time, event_data
FROM events
WHERE device_id = 'zzz'
ORDER BY event_time DESC
LIMIT 10

每個搜尋條件都被索引覆蓋,因此 PostgreSQL 只進行索引掃描。

問題是它會掃描所有子表,然後才會掃描LIMIT 10.

所有這些表的索引都很大,不適合記憶體,因此完成此查詢最多需要 20 秒。

但在大多數情況下,最近的 10 個事件可從一個名為events_p<current_year>_<current_month>.

有沒有辦法在不更改應用程式碼的情況下對 PostgreSQL 中的子表實施“漸進式”掃描?

例如:

events
events_p2019_02 <- and so on...
events_p2019_03 <- scan this if less than 10 rows found in _04 and _05
events_p2019_04 <- scan this if less than 10 rows found in events_p2019_05
events_p2019_05 <- scan this first

我們事先不知道這 10 個事件的可能日期範圍。某些設備可能在最後一天擁有它們,而其他設備可能跨越幾個月(在許多子表中也是如此)。

問題是它掃描所有子表,然後才執行 LIMIT 10。所有這些表的索引都很大,不適合記憶體,因此完成此查詢最多需要 20 秒。

如果您有正確的索引,在這種情況下是on events (device_id,event_time),那麼它只會命中每個索引的一小部分(指向包含每個分區的指定 device_id 的最高 event_time 的葉頁的路徑),並且該部分將可能很容易記憶體,具體取決於存在多少不同的 device_id 並定期查詢。

當版本 12 發佈時,如果您使用聲明性範圍分區而不是通過繼承進行分區,系統將足夠智能以適當的順序命中分區,並且一旦 LIMIT 已經滿足,就不會在更多分區上啟動索引掃描。但是,這可能只是您的情況的一個小改進。如果你有正確的索引,它應該已經很快了,不需要改進,如果你有錯誤的索引,即使有了這個改進,它也可能會慢得令人討厭。

如果您不能等待版本 12 並重構您的分區,並且無法建構適當的索引,那麼手動迭代分區的集合返回函式可能是可行的方法,儘管它很乏味、醜陋和錯誤易於。

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