2013-02-21 58 views
3

我有兩個表在一對多的關係。假設對於表foo中的每一行,表bar中可以有0行或更多行,引用foo中的行。PostgreSQL:count()還是保留一個計數器?

客戶想知道bar中有多少行參考foo中的一行,對於foo中的所有行。

我可以用下面的查詢實現這一點:

SELECT count(bar_id) FROM bar WHERE bar.foo_id = foo.foo_id; 

但是,如果表foobar很大?說foo有100萬行,並且bar有1000萬行。我們還要說foo中99%的行的計數小於1,000 bar行引用它。假設客戶通常每次要求大約100行foo

我應該使用帶外鍵索引的naive count()查詢,還是保留一個計數器會更好?是否有可能保留一個櫃檯?通過使用bar上的觸發器以原子增量和減量更新計數器,我相信這是可能的,但我可能是錯的。

回答

5

也許與直覺相反,您可能會發現簡單的count方法會更快,除非您的工作負載非常偏向於讀取。

原因是計數器表的作用是序列化更新,因此只有一個更新給定foo的事務可以在任何給定時間處於運行狀態。這是因爲更新計數器的觸發器的更新將在計數器表中對foo的條目執行鎖定,並且在事務回滾或提交之前不會釋放它。更糟糕的是,如果您的交易影響多於一個foo,那麼另一個交易會影響其中一個交易由於死鎖而中止的可能性很高。

堅持一個簡單的計數,直到你有一個很好的理由去改變它。

3

索引的甜蜜之處在於它們爲查詢操作提供對數複雜度。因此,對於10*10^6行,索引只需要大約ln(10*10^6)=16.1比較來查找一個特定的ID。使它成爲1億行,而且你只需要做更多的2到3次比較。簡而言之:索引並不太在乎表格的大小。

當然,您仍然可以使用存儲的計數器歸檔一些性能增益。這是一個典型的折衷。維護櫃檯將使bar的插入和刪除更爲昂貴,並使計數查詢更便宜一些。因此,如果您的表很少發生更改,並且查詢頻繁運行(例如,每小時幾千次),那麼使用存儲的計數器過程可能確實會提高性能。但是,在大多數情況下,我會說索引列,並讓數據庫爲你做其餘的。