2016-11-22 25 views
-2

我正在嘗試計算昨天創建的所有記錄。有一個created_at列,它被編入索引。對索引日期時間字段進行計數(*)過濾運行時間太長

如果我運行

explain 
select count(*) from events where created_at::date = current_date - 1; 

它說

Aggregate (cost=14365728.05..14365728.06 rows=1 width=0) 
    -> Index Only Scan using index_events_created_at on events (cost=0.57..14362310.20 rows=1367140 width=0) 
     Filter: ((created_at)::date = (('now'::cstring)::date - 1)) 

所以事件樣的知道有多少行也有。但

select count(*) from events where created_at::date = current_date - 1;

查詢本身保持運行下去。這是爲什麼?

+0

如果使用:'select event(*)from events'會發生什麼? – McNets

+0

「永遠在跑」......你的意思是字面意思,還是跑得比你想的長?如果運行時間很長(但最終會結束),結果是否接近解釋計劃中出現的數字? –

+0

'created_at'是什麼類型? –

回答

1

試試這個:

SELECT count(*) 
FROM events 
WHERE created_at >= current_date - 1 
    AND created_at < current_date; 
1

因此,要啓動:爲什麼解釋計劃能夠提供估計行計數這麼多快於查詢可以運行?

優化器根據存儲的統計信息和/或從存儲的統計信息中推斷出行數。正如你所看到的,這不是非常準確。 (基於評論討論,估計已經下降了近20%)。因此,查詢必須根據表中的數據或索引中的數據進行實際計數。所以這是更多的工作。但這並不是顯而易見的,爲什麼它需要10分鐘的「更多工作」。

一個合理的猜測是鎖定爭用。根據您的事務隔離設置,這可能是因爲您的查詢不得不等待插入或更新表才能完成。 (優化器在計算它的估計值時不會有這個問題,因爲它只會假設併發查詢的效果對於它的目的不是什麼大問題。)即使沒有添加的數據會影響你的計數,表級鎖仍然可能發生衝突。

測試此理論的一種方法是複製表,以便您擁有一張表,其中包含相同的數據(以及相同的索引等),無人查詢,並查看您的計數是否更快地運行。

(順便說一句:一般情況下,當統計數據似乎顯著關閉,你可以懷疑,優化選了一個可憐的執行計劃,但它是很難看到索引掃描可能是錯誤的解決方案在這裏。)