2012-09-18 65 views
28

計算大量數據的表可能非常緩慢,有時需要幾分鐘;它也可能在繁忙的服務器上產生死鎖。我想顯示實際值,NOLOCK不是一個選項。SQL Server計數較慢

我使用的服務器是SQL Server 2005或2008 Standard或Enterprise - 如果它很重要。 我可以想象,SQL Server維護每個表的計數,如果沒有WHERE子句,我可以很快得到這個數字,對吧?

例如:

SELECT COUNT(*) FROM myTable 

應立即返回正確的值。我是否需要依靠統計數據進行更新?

+2

得到一個[查詢執行計劃(http://stackoverflow.com/questions/7359702/how-do -i-obtain-a-query-execution-plan),然後我們可以說...('SELECT COUNT'直接查詢表格而不是使用統計數據,因爲統計數據可能已過時) – Justin

+2

愚蠢的問題,但是你有索引嗎? – Kermit

+0

@FreshPrinceOfSO如果您依靠'Id'(bigint,主鍵,標識規範= true),它仍然很慢。 – ANeves

回答

37

非常接近近似(忽略任何飛行交易)將是:

SELECT SUM(p.rows) FROM sys.partitions AS p 
    INNER JOIN sys.tables AS t 
    ON p.[object_id] = t.[object_id] 
    INNER JOIN sys.schemas AS s 
    ON s.[schema_id] = t.[schema_id] 
    WHERE t.name = N'myTable' 
    AND s.name = N'dbo' 
    AND p.index_id IN (0,1); 

這將返回比COUNT(*)快得多,並且如果您的表格速度變化足夠快,那麼它的準確性並不是那麼低 - 如果您的表格在您開始COUNT和返回時發生了變化,是否更有價值?

+0

也可以在沒有索引存在時使用。 – Kermit

+0

您的解決方案看起來非常有前途,但經過大約5百萬條記錄的測試後,我獲得了相同的響應時間。將很快在較大的數據庫上測試。 – Adi

+2

@Adi對sys.partitions的查詢花了很長時間?我覺得很難相信。 –

8

- 如果我在靜態運行查詢(真大「大量數據」?應該有評論這個第一,但也許下面的EXEC幫助你的話)

(指沒有其他人討厭讀/寫/更新在很長一段時間,所以爭用不是問題)在我的開發機器(oracle)上有2億行和COUNT(*)15秒鐘的表。 考慮到數據的純量,至於你說NOLOCK是不是一種選擇,這仍是相當快(至少對我來說)

,你可以考慮

exec sp_spaceused 'myTable' 

爲好。

但是這腳下跌近於相同NOLOCK(忽略爭+刪除AFAIK /更新)

2

Count將執行表掃描或索引掃描。所以對於大量的行,它會很慢。如果您經常執行此操作,最好的方法是將計數記錄保存在另一個表中。

然而,如果你不想做,你可以創建一個虛擬指數(不會被查詢的使用)和查詢它的項目的數量,是這樣的:

select 
    row_count 
from sys.dm_db_partition_stats as p 
inner join sys.indexes as i 
    on p.index_id = i.index_id 
    and p.object_id = i.object_id 
where i.name = 'your index' 

我的建議創建一個新的索引,因爲這個(如果它不會被使用)在其他操作期間不會被鎖定。

正如Aaron Bertrand所說,維護查詢可能會更昂貴,然後使用已有的查詢。所以選擇是你的。

+0

但即使該索引不用於其他*讀取*操作,它仍然需要維護其他DML。我認爲這個虛擬指數比你想象的要昂貴。 –

+0

它可能如你所說。它必須經過測試。可以在不創建實際的新索引的情況下使用sql,而是在現有索引上使用。我在過濾索引上使用了類似的東西。我從來不需要從頭到尾統計桌子。 –

0

如果你只需要粗略的行數,即。確保一個表中加載正確或以確保數據沒有被刪除,請執行下列操作:

MySQL> connect information_schema; 
MySQL> select table_name,table_rows from tables;