2014-09-06 90 views
0

查詢A執行以微秒:爲什麼添加一個窗口函數使得這個查詢很慢?

SELECT t1.id 
FROM (SELECT t0.id AS id FROM t0) AS t1 
WHERE NOT (EXISTS (SELECT 1 
     FROM t2 
     WHERE t2.ph_id = t1.id AND t2.me_id = 1 AND t2.rt_id = 4)) 
LIMIT 20 OFFSET 0 

但查詢乙大約需要25秒時:

SELECT t1.id, count(*) OVER() AS count 
FROM (SELECT t0.id AS id FROM t0) AS t1 
WHERE NOT (EXISTS (SELECT 1 
     FROM t2 
     WHERE t2.ph_id = t1.id AND t2.me_id = 1 AND t2.rt_id = 4)) 
LIMIT 20 OFFSET 0 

(所不同的是在選擇子句中只有一個項目 - 一個窗口集合)

EXPLAIN輸出如下,對於A:

Limit (cost=0.00..1.20 rows=20 width=4) 
    -> Nested Loop Anti Join (cost=0.00..3449.22 rows=57287 width=4) 
     Join Filter: (t2.ph_id = t0.id) 
     -> Seq Scan on t0 (cost=0.00..1323.88 rows=57288 width=4) 
     -> Materialize (cost=0.00..1266.02 rows=1 width=4) 
       -> Seq Scan on t2 (cost=0.00..1266.01 rows=1 width=4) 
        Filter: ((me_id = 1) AND (rt_id = 4)) 

而對於B:

Limit (cost=0.00..1.45 rows=20 width=4) 
    -> WindowAgg (cost=0.00..4165.31 rows=57287 width=4) 
     -> Nested Loop Anti Join (cost=0.00..3449.22 rows=57287 width=4) 
       Join Filter: (t2.ph_id = t0.id) 
       -> Seq Scan on t0 (cost=0.00..1323.88 rows=57288 width=4) 
       -> Materialize (cost=0.00..1266.02 rows=1 width=4) 
        -> Seq Scan on t2 (cost=0.00..1266.01 rows=1 width=4) 
          Filter: ((me_id = 1) AND (rt_id = 4)) 

我加入窗口集合限制之前得到排的總數,爲建設一個分頁UI的目的。

回答

3

原始查詢可以這樣寫:

SELECT t0.id 
FROM t0 
WHERE NOT EXISTS (SELECT 1 
        FROM t2 
        WHERE t2.ph_id = t1.id AND t2.me_id = 1 AND t2.rt_id = 4 
       ) 
LIMIT 20 OFFSET 0; 

你沒有order by,所以查詢可以開始返回結果,因爲他們發現結果集。當你添加窗口函數時:

SELECT t.0.id, count(*) over() 

現在它正在計算結果集中的行數,所以它必須生成整個結果集。因此,查詢不必只是獲得前20行,而是必須生成所有這些查詢。這需要更多時間。

2

你可以檢查長COUN(*)如何進行,哪些執行計劃是這樣的:

SELECT count(*) 
FROM (SELECT t0.id AS id FROM t0) AS t1 
WHERE NOT (EXISTS (SELECT 1 
     FROM t2 
     WHERE t2.ph_id = t1.id AND t2.me_id = 1 AND t2.rt_id = 4)) 

爲什麼它需要更長的時間,這可能會給你的想法。

基本上,第一個查詢只能讀取20條與t0條件匹配的第一條記錄,而第二條查詢必須生成符合標準的完整記錄集才能對它們進行計數。

0

感謝您的其他答案,這是正確的,計數必須做更多的工作,但我從另一個來源找到解決方案。統計信息不是最新的。

運行命令後...:

ANALYZE; 

... PostgreSQL的是能夠選擇更合適的查詢計劃,而現在這兩個查詢運行速度非常快。

相關問題