2012-09-13 74 views
0

是的我知道這個問題是類似於這個線程:COUNT(*) vs. COUNT(1) vs. COUNT(pk): which is better?,但這有點不同。有沒有任何性能改善計數(PK)對數(*)

我的前輩說,從count(PrimaryKey)得到的結果,假設PrimaryKey不能NULL,是某種比做正常count(*)更快。這是真的?

如果這是真的,對所有的RDBMS都是這樣嗎?如果可能的話,請參考(半)官方文件。

+0

@Ian不可能的:你真的看過我的第一次發言有關的可能性它是相似的? – zfm

+0

我做了,然後在某個地方忘了它 - 對不起,我會盡力讓你的一些研究:) –

回答

0

有幾個原因沒關係。首先,兩個符號 - COUNT(1)COUNT(*) - 都是錯誤的語法。考慮關於SUM聚合的相同問題。哦,SUM(*)沒有任何意義;爲什麼?因爲,求和是賦值

for(int columnValue : columnList) 
    currentSum = currentSum + columnValue; 

的迭代執行,而對於COUNT骨料它看起來像這樣

for(Tuple t : tupleList) 
    currentSum = currentSum + 1; 

因此,COUNT合計不應該有任何參數了!

然後,有各種各樣的語法怪癖,如計數不同。這簡直證明了試圖將兩個連續操作(選擇不同的元組,然後聚合)壓縮到一個操作的SQL設計者的無能。

無關緊要的第二個原因是在實踐中您會遇到無數表現不佳的查詢,並且COUNT(1) vs COUNT(*)永遠不是瓶頸。

+0

'COUNT'需要一個可選參數 - 如果給定,它將不會計算行該表達式的計算結果爲'NULL' - 請參閱http://www.postgresql.org/docs/9.2/static/functions-aggregate.html –

+0

因此,您不能先過濾出空值,然後再計數嗎?換句話說,您可以解釋兩次操作的組合,而不是爲每個使用場景引入笨拙的語法。 –

+0

所有SQL聚合函數都會跳過空值:SUM,COUNT,MIN,MAX,AVERAGE等COUNT(*)是奇數。如果你必須先過濾掉,你將無法做到像SELECT COUNT(column_a),COUNT(column_b)FROM table'這樣的東西來計算兩個不同列中的非空值。 –

2

號這似乎是一個持久的誤解,基於語法之間的混淆

SELECT * FROM ... 

SELECT COUNT(*) FROM ... 

在第一種情況下,*指所有列,並返回那些肯定需要比返回單個列更多的資源。在第二種情況下,COUNT(*)只是「計數所有行」的簡寫。錯誤的看法是,COUNT(*)以某種方式指示數據庫引擎檢查所有行中的所有列,而COUNT(<pk_field>)只需查看一列。

在這裏有很多關於SO的其他評論引用了SQL-92標準,其中明確指出COUNT(*)應該只引用表的基數,所以至少在理論上,數據庫引擎應該能夠認識和優化。

據我所知,在這兩種情況下,大多數數據庫引擎(Postgres,Oracle, MySQL InnoDB)只會執行索引掃描來計算行數。如果您指定PK,那麼將使用該索引;如果您只使用COUNT(*),那麼查詢計劃器將選擇一個跨越整個表*的索引,但性能應該相同。

我能找到的唯一例外是MySQL和MyISAM表 - 這些表緩存行數,所以COUNT(*)速度非常快。但是,查詢計劃程序還會將COUNT(<field>)(其中<field>是任何非空列)識別爲全表大小的請求,並在該情況下也使用高速緩存。 (source)所以再次,性能沒有差異。

*理論上,如果你沒有這樣的索引,然後COUNT(*)會很慢,但在這種情況下,COUNT(<pk>)將是定義