2012-07-25 47 views
0

我最近回答根據我的經驗,這個問題:預取的行數 - 性能

Counting rows before proceeding to actual searching

,但我不是100%滿意,我給出了答案。

問題基本上是這樣的:在決定運行實際返回的查詢之前,可以通過在特定查詢上運行COUNT來獲得性能改進嗎?

我的直覺是這樣的:您將只保存與檢索數據相關的I/O和連線時間而不是計數,因爲要計數數據,您需要實際查找行。可能的例外是查詢是索引的簡單函數。

我的問題是這樣的:這是真的嗎?還有哪些其他異常情況?從純粹的性能角度來看,在運行完整查詢之前,需要在什麼情況下執行COUNT

回答

1

首先,您的問題的答案高度依賴於數據庫。

在查詢之前執行COUNT()時,我無法想象會縮短查詢和count()的總時間。

通常,執行計數將預加載表和索引到頁面緩存中。假設數據適合內存,這將使後續查詢運行得更快(儘管如果您有快速I/O並且數據庫執行預讀頁讀取,速度會更快)。但是,您剛剛將時間範圍轉換爲COUNT(),而不是縮短總體時間。

爲了縮短總體時間(包括COUNT()的運行時間),需要更改執行計劃。理論上有兩種方法:

  1. 數據庫可以在讀入表時更新統計信息,而這些統計信息反過來會更改主查詢的查詢計劃。
  2. 數據庫可以根據表/索引是否已存在於頁面緩存中來更改執行計劃。

雖然理論上可行,但我沒有意識到任何數據庫都能執行這些操作。

你可以想象中間結果可以被存儲,但這會違反SQL數據庫的動態特性。也就是說,更新/插入可能發生在COUNT()和查詢之間的表上。數據庫引擎無法保持完整性並維護這樣的中間結果。

與加速後續查詢相比,執行COUNT()具有缺點。 COUNT()的查詢計劃可能與主查詢的查詢計劃完全不同。您的索引示例就是一種情況。另一種情況是列式數據庫,不需要讀取數據的不同垂直分區。

又一情況下將是一個查詢,例如:

select t.*, r.val 
from table t left outer join 
    ref r 
    on t.refID = r.refID 

和REFID是裁判表的唯一索引。由於沒有重複記錄並且使用了t中的所有記錄,因此可以刪除此聯接計數。但是,該查詢顯然需要連接。再一次,SQL優化器是否能夠識別並處理這種情況完全取決於數據庫編寫者的決定。但是,理論上可以爲COUNT()優化連接。