FROM 子句中的相關函式是否針對每一行執行?
我有一個很重的功能,我們稱之為
fcalc(x,y) -> my_z
. 我需要結果my_z
既是過濾器(太低並且該行被丟棄)又是結果集中(以便我的客戶可以看到它)。我這樣寫查詢:SELECT *, my_z FROM big_table t, (SELECT * FROM fcalc(t.x, t.y)) as my_z WHERE condition1 AND condition2 AND ... AND my_z > $threshold
我的問題是:所有其他條件是否會首先應用,在應用之前應該過濾掉非常多的行
fcalc
?我對數據庫很陌生。
不,Postgres 通常不會
LATERAL
為所有行評估子查詢中的函式。它將
big_table
首先應用簡單的過濾器並僅對仍在競爭中的行執行該函式。修復問題
您的查詢在語法上無效。
假設
fcalc()
返回一個值,這將起作用:SELECT * , my_z FROM big_table t, **LATERAL** (SELECT * FROM fcalc(tx, ty)) AS **f(my_z)** WHERE $condition1 AND $condition2 AND ... AND **f.my_z > $threshold**
並且應該解開只是:
SELECT * FROM big_table t JOIN LATERAL fcalc(t.x, t.y) AS f(my_z) ON f.my_z > $threshold WHERE $condition1 AND $condition2 AND ...
將
f.my_z > $threshold
fromWHERE
子句移動到連接條件使查詢更易於閱讀,並且對查詢計劃沒有任何影響(使用 時[INNER] JOIN
)。這會產生完全相同的查詢計劃:SELECT * FROM big_table t, fcalc(t.x, t.y) f(my_z) WHERE $condition1 AND f.my_z > $threshold AND $condition2 AND ...
查詢計劃
在執行和過濾結果之前
big_table
,任何一個固定查詢都將首先應用過濾行的謂詞。fcalc()
您可以使用
EXPLAIN ANALYZE
. 假設您big_table
有 8 行,其中 5 行未通過您的$conditionN
過濾器,其餘 3 行中的 1 行未通過f.my_z > $threshold
。你會看到類似的東西:嵌套循環(成本=0.00..1.17 行=3 寬度=79)(實際時間=0.026..0.027 行=1 循環=1) -> big_table t 上的 Seq Scan(成本=0.00..1.10 行=3 寬度=75)(實際時間=0.007..0.009 行=3 循環=1) 過濾器:(id > 5) **過濾器刪除的行數:5** -> 對 fcalc f 進行函式掃描(成本=0.00..0.02 行=1 寬度=4) (實際時間=0.005..0.005 行=0**循環=3**) 過濾器:(my_z > 9) **過濾器刪除的行數:1** 規劃時間:0.101 ms 執行時間:0.043 毫秒
意思
fcalc()
是,在範例中只執行了 3 次。實際上,您應該看到大表的索引掃描,但都是一樣的。如果在執行查詢之前將 GUC 設置
track_functions
為,則可以進一步驗證這一點。手冊:pl``EXPLAIN ANALYZE
啟用對函式呼叫計數和使用時間的跟踪。指定
pl
僅跟踪過程語言函式,all
同時跟踪 SQL 和 C 語言函式。預設值為none
,禁用函式統計跟踪。只有超級使用者可以更改此設置。筆記
無論此設置如何,都不會跟踪簡單到可以“內聯”到呼叫查詢中的 SQL 語言函式。
然後檢查在執行查詢之前和之後實際呼叫函式的頻率:
SELECT calls FROM pg_catalog.pg_stat_user_functions WHERE funcid = 'fcalc'::regproc
有關演員
'fcalc'::regproc
表的詳細資訊,請參閱手冊。在旁邊
Postgres 還將根據它們的估計成本對同一級別的過濾器進行優先級排序。您可以使用我上面列出的工具進行驗證。修補
COST
簡單 plpgsql 函式的設置…