我們有時會遇到一些坑,要不填平,要不繞過.這里為大家介紹一個相關SQL Server優化器方面的特性導致內存授予的相關BUG,及相關解決方式,也順便回答下鄒建同學的相關疑問.
問題描述
一個簡單的查詢消耗了匪夷所思的內存.(鄒建同學發現的)
Code
create table test_mem ( id int identity(1,1) primary key, itemid int not null, date datetime not null, str1 varchar(max) null ) INSERT test_mem( itemid,date ) SELECT TOP(1000) ABS(CHECKSUM(NEWID())) % 200, DATEADD(day, CHECKSUM(NEWID()) % (3 * 360), GETDATE()) FROM sys.all_columns A, sys.all_columns B go 100 select * from test_mem where itemid=28 order by date
執行代碼后執行計划如圖1-1
圖1-1
可以看出如此小的數據集排序居然消耗如此恐怖的內存數據量級,這樣簡單查詢如果數據量再大些完全可能嚴重影響吞吐.
問題分析:通過執行計划我們發現只是一個簡單的聚集索引掃描加上一個排序.問題就出現在聚集索引掃描上,通過語義分析我們發現我們的那個Itemid=28也包含在聚集索引掃描中過濾了,但優化器在做內存評估時並未注意到此狀況,還是按照全表的相關內存大小評估的.
我們可以根據行大小大概算出優化器”認為”的數據大小.
Select 100000.0*4051.0/1024.0/1024.0 (約等於386MB!)
原來優化器以為他要對386MB的數據排序…
問題總結:優化器在做聚集索引掃描時同時為我們做了Filter過濾,但對接下來的內存評估時確忽略了運算符中的過濾.致使內存評估出現嚴重問題.
解決:了解了問題點后解決就簡單了.在去年6月份的Pass分享中我曾經提過Filter運算符,我們只需讓他在我們的執行計划中重現即可.
Trace Flag 9130 可以使得這個運算符可以重現.
Code
select * from test_mem where itemid=28 order by date option(querytraceon 9130)
可以通過執行計划看出,內存授予正常,如圖1-2所示
圖1-2
注:此坑一旦踩上影響着實不小,看到的朋友請擴散.
后記:此問題我已經反應給微軟的CSS團隊.
