我有一個簡單的問題。不知何故,我無法找到明確的答案。PostgreSQL WITH RECURSIVE性能
在PostgreSQL中對WITH RECURSIVE
語法進行了多少優化?我的意思是:它僅僅是一系列非遞歸查詢的語法糖,或者它更像是一個單一的語句,儘管其複雜的語義作爲一個整體進行了優化。一個後續問題 - 幾乎可以優化這種類型的語法?當然,有關這個問題的一些具體數據是最受歡迎的。
我有一個簡單的問題。不知何故,我無法找到明確的答案。PostgreSQL WITH RECURSIVE性能
在PostgreSQL中對WITH RECURSIVE
語法進行了多少優化?我的意思是:它僅僅是一系列非遞歸查詢的語法糖,或者它更像是一個單一的語句,儘管其複雜的語義作爲一個整體進行了優化。一個後續問題 - 幾乎可以優化這種類型的語法?當然,有關這個問題的一些具體數據是最受歡迎的。
我的經驗是它確實非常好的優化。
檢查出所產生您查詢的執行計劃EXPLAIN分析和您將看到如何「昂貴」,它確實是(然後是如比較書面自遞歸函數)
我已經發現它優化到了一個點。
各個子查詢按預期重新使用並單獨優化,Postgres優化後者,就像任何其他查詢一樣。
我的主要抱怨是,它不會向CTE注入約束條件。
例如:
with recursive
parents as (
select node.id,
node.parent_id
from nodes as node
union all
select node.id,
parent.parent_id
from parents as node
join nodes as parent on parent.id = node.parent_id
)
select parent_id
from parents
where id = 2;
Postgres的理想地理解,在上面的,是(因爲node.id返回爲是),它可以這樣做:
with recursive
parents as (
select node.id,
node.parent_id
from nodes as node
where id = 2
union all
select node.id,
parent.parent_id
from parents as node
join nodes as parent on parent.id = node.parent_id
)
select parent_id
from parents;
...並在主鍵上使用索引掃描。實際上,它實際上是在CTE告訴它做的時候完成的:遞歸地拉出所有行的所有父項,如果需要,將結果集放在一個未命名的臨時表中,然後檢查結果集中的每一行以獲得id = 2.
換句話說,CTE不保留它返回的「始發」表/行/列集的跟蹤。在正確優化之前,在遞歸查詢上創建視圖最多是瘋狂的。
一個很好的解決辦法在此期間是不是創建一個SQL函數:
create function parents(id int) as returns table (id int) $$
with recursive
parents as (
select node.id,
node.parent_id
from nodes as node
where id = $1
union all
select node.id,
parent.parent_id
from parents as node
join nodes as parent on parent.id = node.parent_id
)
select parent_id
from parents;
$$ language sql stable strict rows 5 cost 1;
的另一個問題是,你不能用遞歸CTE的更新使用(對於大同小異的理由,其實)。
鑑於這個答案的年齡,你是否知道你描述的行爲有任何近期的變化? – 2017-07-20 09:56:31
@OliverSalzburg:我真的不知道,但通過比較答案中查詢的查詢計劃,應該很容易進行測試。 – 2017-07-20 10:16:25
在語言層面擁有'WITH RECURSIVE'的全部原因是數據庫知道你正在嘗試做什麼,然後可以根據你的意圖採取行動。 – 2011-05-02 19:32:40
@mu Yea,那就是我所認爲的。然而,即使在數據庫級別上,通過使用索引等來優化它也不是很明顯。一些操作通常很困難。遵循這個建議,我會盡快發佈我的發現。 – julkiewicz 2011-05-02 19:59:10
@julkiewicz傳遞閉包表實際上是這樣的查詢的索引。我沒有理由找不到使用類似技術的索引類型。 – EricS 2013-09-10 08:31:48