2012-12-06 17 views
1

我有一些列包括列datekey(這是一個date和具有索引)的表MYTABLE,列contents其是varbinary(max)和列stringhash其是varchar(100)stringhashdatekey一起組成表格的主鍵。一切都在我的本地機器上運行。添加數據長度條件使得查詢慢

運行

SELECT TOP 1 * FROM mytable where datekey='2012-12-05' 

返回0行和取0秒。 但是,如果我添加datalength條件:

SELECT TOP 1 * FROM mytable where datekey='2012-12-05' and datalength(contents)=0 

它運行了很長一段時間,我才放棄等待不返回任何東西。我的問題: 爲什麼?我如何知道爲什麼需要這麼長時間?


這是我檢查迄今:

當我點擊「顯示估計的執行計劃」還需要很長的時間,我才放棄等待不返回任何東西。

如果我做

SELECT TOP 1000 datalength(contents) FROM mytable order by datalength(contents) desc 

需要7秒,返回一個列表4228081,4218689等

exec sp_spaceused 'mytable' 

回報

rows  reserved  data   index_size unused 
564019  50755752 KB 50705672 KB 42928 KB 7152 KB 

所以該表是在50相當大GB。 跑步

SELECT TOP 1000 * FROM mytable 

需要26秒。

sqlservr.exe進程大約是6 GB,這是我爲數據庫設置的限制。

回答

3

這需要很長時間,因爲您的查詢需要爲每行評估DATALENGTH,然後將結果排序,然後才能返回第一條記錄。 如果字段的DATALENGTH(或者它是否包含任何值)是您可能反覆查詢的內容,那麼我會建議一個額外的索引字段(可能是一個持續計算字段)來保存結果,然後在其上進行搜索。

0

目前它可能不會使用主鍵,因爲在datekey列之前包含了stringhash列。嘗試添加一個僅包含datekey列的附加索引。一旦如果它仍然緩慢,你也可以嘗試查詢提示如項中創建:

SELECT TOP 1 * FROM mytable where datekey='2012-12-05' and datalength(contents)=0 WITH INDEX = IX_datekey 

你也可以創建要麼在你的應用程序或在插入/更新觸發更新一個單獨的長度列。

0

這個舊的msdn blog post似乎同意@MartW的答案,datalength被評估爲每一行。但很好理解「評估」的真正含義,以及性能下降的真正根源是什麼。

正如問題所述,列contents中每個值的大小可能很大。這意味着每個大於〜8Kb的值都存儲在特殊的LOB存儲中。所以,考慮到其他列的大小,很明顯,該表佔用的大部分空間都是由該LOB存儲器佔用的,即大約50Gb。

即使已經對每行的contents列的長度進行了評估(這在後面的鏈接中已得到證實),但它仍存儲在LOB中。所以引擎仍然需要讀取LOB存儲的某些部分來執行查詢。

如果在查詢執行時LOB存儲不在RAM中,那麼我們需要從磁盤讀取它,這當然比從RAM讀取要慢。 LOB部分的讀取也可能比線性更隨機化,因爲它往往會提高需要從磁盤中讀取的整個內存塊的數量,所以速度更慢。