Postgresql

如何優化將 IN 子句替換為多個 UNION ALL 的查詢?

  • January 20, 2018

我有一個這樣的查詢:

select *
from slow_view
where id = 1
union all
....
union all
select *
from slow_view
where id = 1000

-- 50 ids, exec time: 10.615 sec, 

如果將其替換為以下內容,這將在非常可接受的時間內執行:

select *
from slow_view
where id in (1, ...., 1000)

-- 50 ids, exec time: 1.3 sec, 

要麼

with slow_view_cached as (
select * from slow_view)
select *
from slow_view_cached
where id = 1
union all
....
union all
select *
from slow_view_cached
where id = 1000

-- 50 ids, exec time: 1.83 sec, 

但不幸的是,它是由ORM生成的,我沒有機會修改它。作為一個 ORM,它非常糟糕,我認為我不能做太多事情來改善它的行為。

在這種情況下,我可以對我的查詢或視圖做些什麼來使其“記憶體”所有子查詢?我知道我可以使用物化視圖,但它不太適合我的情況。

Postgres 中的 AFAIK 無法在視圖上定義索引,因此id不是索引或唯一的。

還有什麼我可以嘗試的嗎?

我正在使用 Postgresql 9.5(但如果您有針對 PG 9.6 甚至 PG 10 的解決方案,這是可以接受的,因為我計劃很快更新)。

程式碼有點太複雜,無法在此處發布。本質上,此查詢是在以下情況下生成的。slow_view是模型 m 的關聯。我所做的基本上是m.find().populate(slow_view, criteria);文件在這裡

為了簡單起見,從查詢中排除了條件,id 是從 slow_view 到 Model 的外**鍵

可以從這個 ORM 中呼叫一個儲存過程,但這意味著對應用程序的改動太多了。

如果slow_view沒有太多記錄,您可以考慮將所有記錄提取到應用程序並在應用程序端結果集中應用過濾器。這種方法在特定情況下幫助我減少了數據庫負載。

社區維基回答

在執行包含視圖名稱而不是表名稱的查詢之前,Postgres 將執行一個稱為視圖解析的步驟。此步驟會將視圖的 select 語句定義復製到您執行的 select 語句中。如果您在源表中的 ID 列上有索引,則將使用該索引。否則,如果 ID 是來自多個源表的多個列的替身,您可以創建一個具有適當索引的物化視圖。

如果 ID 是源表中的單個列,則物化視圖不太可能加快查詢速度,因為第一個和第二個查詢在結構上是不同的。在第一種情況下,Postgres 進行 1000 個(如果您的範例實際上有很多不同的 ID 值)單個查詢並將所有結果連接到單個結果游標中。在第二個查詢中,Postgres 能夠看到全域,並且可以更好地選擇從索引中選擇的策略(例如範圍掃描)。

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