2011-06-21 105 views
7

我有一個查詢如下;慢SQL性能

SELECT COUNT(Id) FROM Table 

該表包含33萬條記錄 - 它包含一個Id上的主鍵並且沒有其他索引。

查詢需要30秒。

實際執行計劃顯示它使用聚簇索引掃描。

我們已經分析表,發現它是用在這個環節中所示的第一查詢不分散:http://sqlserverpedia.com/wiki/Index_Maintenance

任何想法爲什麼這個查詢是如此之慢,以及如何解決它。

表定義:

CREATE TABLE [dbo].[DbConversation](
[ConversationID] [int] IDENTITY(1,1) NOT NULL, 
[ConversationGroupID] [int] NOT NULL, 
[InsideIP] [uniqueidentifier] NOT NULL, 
[OutsideIP] [uniqueidentifier] NOT NULL, 
[ServerPort] [int] NOT NULL, 
[BytesOutbound] [bigint] NOT NULL, 
[BytesInbound] [bigint] NOT NULL, 
[ServerOutside] [bit] NOT NULL, 
[LastFlowTime] [datetime] NOT NULL, 
[LastClientPort] [int] NOT NULL, 
[Protocol] [tinyint] NOT NULL, 
[TypeOfService] [tinyint] NOT NULL, 
    CONSTRAINT [PK_Conversation_1] PRIMARY KEY CLUSTERED 
(
[ConversationID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
GO 

有一件事我注意到的是數據庫設置中的1Mb塊增長。

它是一個活的系統,所以我們在我們可以玩的限制 - 任何想法?

UPDATE:

OK - 我們已經通過相應的列添加新的非聚集索引,所以它不是一個嚴重的問題了改善的實際感興趣的查詢性能。

SELECT COUNT仍然緩慢,但 - 與NOLOCK提示嘗試了 - 沒有什麼區別。

我們都認爲這與自動增長設置爲1Mb而不是更大的數字有關,但令人驚訝的是它具有這種效果。磁盤上的MDF碎片可能是一個可能的原因?

+1

問題1:你確實需要確切的數量嗎?或者只是一個估計? –

+0

兩者都沒有 - 這只是我們在觀察其他內容的慢速性能之後所執行的查詢。我們很驚訝地發現它太慢了。要嘗試更新統計信息,但他們設置爲自動更新。 – BonyT

+0

你不能只用一個常量嗎?我的意思是,它有3300萬的差異呢?或者它有33.212.293條記錄對你有什麼影響? – bevacqua

回答

5

這是一個頻繁讀取/插入/更新表?是否有更新/插入活動與您的選擇同時發生?

我的猜測是延遲是由於爭用。

我可以在17秒內在我的開發服務器上運行一個189m行的計數,但沒有其他東西打到該表。

如果你不是太擔心競爭或絕對準確,你可以這樣做:

exec sp_spaceused 'MyTableName',這將給基於元數據的計數。

如果你想要一個更精確的計數,但不一定在乎它是否反映併發DELETEINSERT活動,你可以用NOLOCK提示能做你現在查詢:

SELECT COUNT(id) FROM MyTable WITH (NOLOCK)這不會得到行級鎖您的查詢並運行得更快。

+0

不是一個非常繁忙的數據庫 - 爭用不是一個問題(聲明幾乎總是需要完全相同的時間來響應30秒,並使用NOLOCK提示沒有任何區別。) – BonyT

+0

@BonyT - 那麼你還有其他一些問題。這張桌子有多寬?這與'COUNT'沒有直接關係,但它確實影響SQL需要拉多少頁來獲取計數,這在更高的卷中可能很重要。你還有什麼其他性能問題? – JNK

+0

已接受,雖然可能永遠不會知道實際問題在這裏,因爲在某人的地盤上,他們已經設置了我瞭解的解決方法。 – BonyT

1
use [DatabaseName] 

select tbl.name, dd.rows from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

select sum(dd.rows)from sysindexes dd 
inner join sysobjects tbl on dd.id = tbl.id where dd.indid < 2 and tbl.xtype = 'U' 

通過使用這些查詢,你可以在那裏根據您的要求條款0-5秒

使用中獲取所有表計數.....

+0

參考網站是:http://planetofcoders.blogspot.com/2011/06/how-to-count-all-rows-in-particular.html –

+1

仔細閱讀這篇文章,他的關注不是'select count(id )查詢的性能相當慢 – Rahul

2

思考:

  • 使用SELECT COUNT(*)這是 「多少行」 正確的(根據ANSI SQL)。即使ID是PK並因此不可爲空,SQL Server也會計數ID。不是行。

  • 如果您可以使用近似計數,則使用sys.dm_db_partition_stats。看到這裏我的答案:Fastest way to count exact number of rows in a very large table?

  • 如果你能活髒讀使用WITH (NOLOCK)

+0

真正無關緊要,因爲無論您放在括號內,優化程序都會有效地使用相同的計劃。有些人對使用「*」很挑剔。無論這與問題無關。 – BonyT

+0

@BonyT:如果你認爲這是「挑剔」,我建議你驗證我[*]意識到[差異](http://stackoverflow.com/questions/1221559/count-vs-count1/1221649#1221649),但計數(col)可能不會提供與count(*)相同的計劃。因此,我的建議 – gbn

+0

是的,我們有 - 我們實際上是以* :)開頭的 – BonyT

0

另一個想法:當文件增長具有1MB的部分,它可以在文件系統上進行分段。您無法通過SQL查看它,您可以使用磁盤碎片整理工具查看它。