今天的文章里我想談下SQL Server里非常普遍的問題:如何處理用自增長鍵列的統計信息。我們都知道,在SQL Server里每個統計信息對象都有關聯的直方圖。直方圖用多個步長描述指定列數據分布情況。在一個直方圖里,SQL Server最大支持200的步長,但當你查詢的數據范圍在直方圖最后步長后,這是個問題。我們來看下面的代碼,重現這個情形:
1 -- Create a simple orders table 2 CREATE TABLE Orders 3 ( 4 OrderDate DATE NOT NULL, 5 Col2 INT NOT NULL, 6 Col3 INT NOT NULL 7 ) 8 GO 9 10 -- Create a Non-Unique Clustered Index on the table11 CREATE CLUSTERED INDEX idx_CI ON Orders(OrderDate)12 GO13 14 -- Insert 31465 rows from the AdventureWorks2008r2 database15 INSERT INTO Orders (OrderDate, Col2, Col3) SELECT OrderDate, CustomerID, TerritoryID FROM AdventureWorks2008R2.Sales.SalesOrderHeader16 GO17 18 -- Rebuild the Clustered Index, so that we get fresh statistics.19 -- The last value in the Histogram is 2008-07-31.20 ALTER INDEX idx_CI ON Orders REBUILD21 GO22 23 -- Insert 200 additional rows *after* the last step in the Histogram24 INSERT INTO Orders (OrderDate, Col2, Col3)25 VALUES ('20100101', 1, 1)26 GO 200
在索引重建后,我們再看下直方圖,我們發現最后步進的值是2008-07-31。
1 DBCC SHOW_STATISTICS('dbo.Orders', 'idx_CI') WITH HISTOGRAM
你已經看到,在最后步進到表里后,我們插入了200條額外記錄。這樣的話,直方圖并沒有真實反饋實際的數據分布情況,但SQL Server還是要進行基數計算。我們現在來看看在不同版本里SQL Server是如何處理這個問題的。
SQL Server 2005 SP1- SQL Server 2012在SQL Server 2014之前,基數計算對此問題的處理非常簡單:SQL Server估計行數為1,你可以從下面的圖片里看到。
點擊工具欄的顯示包含實際的執行計劃,并執行如下查詢:
SELECT * FROM dbo.Orders WHERE OrderDate='2010-01-01'
自SQL Server 2005 SP1起,查詢優化器可以標記1列為自增長(Ascending)來克服剛才介紹的限制。如果你用自增長列值更新了統計信息對象3次,那列就會被標記為自增長列。為了看有沒有列標記為自增長,你可以使用跟蹤標記2388。當你啟用這個跟蹤標記,DBCCSHOW_STATISTICS的輸出就改變了,有額外列返回。
DBCC TRACEON(2388)DBCC SHOW_STATISTICS('dbo.Orders', 'idx_CI')
現在下面的代碼更新統計信息3次,每次用自增長鍵列值在我們聚集索引末尾插入行。
1 -- => 1st update the Statistics on the table with a FULLSCAN 2 UPDATE STATISTICS Orders WITH FULLSCAN 3 GO 4 5 -- Insert 200 additional rows *after* the last step in the Histogram 6 INSERT INTO Orders (OrderDate, Col2, Col3) 7 VALUES ('20100201', 1, 1) 8 GO 200 9 10 -- => 2nd update the Statistics on the table with a FULLSCAN11 UPDATE STATISTICS Orders WITH FULLSCAN12 GO13 14 -- Insert 200 additional rows *after* the last step in the Histogram15 INSERT INTO Orders (OrderDate, Col2, Col3)16 VALUES ('20100301', 1, 1)17 GO 20018 19 -- => 3rd update the Statistics on the table with a FULLSCAN20 UPDATE STATISTICS Orders WITH FULLSCAN21 GO
然后,當我們執行DBCC SHOW_STATISTICS命令,你會看到SQL Server已講那列標記為Ascending。
DBCC TRACEON(2388)DBCC SHOW_STATISTICS('dbo.Orders', 'idx_CI')
現在當你再次執行查詢不是直方圖范圍的數據時,沒有任何改變。為了使用標記為自增長鍵列,你要啟用另外一個跟蹤標記-2389。如果你啟用這個跟蹤標記,查詢優化器就是密度向量(Density Vector)來進行基數計算。
-- Now we query the newly inserted range which is currently not PResent in the Histogram.-- With Trace Flag 2389, the Query Optimizer uses the Density Vector to make the Cardinality Estimation.SELECT * FROM OrdersWHERE OrderDate = '20100401'OPTION (RECOMPILE, QUERYTRACEON 2389)GO
來看下現在的表密度:
DBCC TRACEOFF(2388)DBCC SHOW_STATISTICS('dbo.Orders', 'idx_CI')
現在的表密度是0.0008873115,因此查詢優化器的估計行數是28.4516:0.0008873115*(32265-200)。
這雖然不是最好的結果,但比估計行數1好很多!
(這里有問題,我本地是SQL Server 2008r2,測試估計行數還是1,不知原因,望知道的朋友解釋下,多謝!
)
SQL Server 2014在SQL Server 2014引入的一個新功能是新基數計算。新基數計算對于自增長鍵問題的處理非常簡單:默認不使用任何跟蹤標記,來使用統計信息對象的密度向量來進行基數計算。下面查詢啟用2312跟蹤標記的基數計算來運行同個查詢。
1 -- With the new Cardinality Estimator SQL Server estimates 28.4516 rows at the Clustered Index Seek Operator.2 SELECT * FROM Orders3 WHERE OrderDate = '20100401'4 OPTION (RECOMPILE, QUERYTRACEON 2312)5 GO
我們來看這里的基數計算,你會看到查詢優化器再次估計行數是28.4516,但這一次沒表上自增長。這是SQL Server 2014的自帶功能。
(SQL Server 2014測試失敗,估計行數也是1……)
小結在這篇文章,我向你展示了SQL Server的查詢優化器如何處理自增長鍵問題。在SQL Server 2014之前,你需要啟用2389跟蹤標記來獲得更好的基數計算——這樣的話那列會標記為自增長(ascending)。SQL Server 2014,查詢優化器默認就使用密度向量來進行基數計算,這樣就方便很多。我希望你對此有所收獲,在SQL Server里如何處理自增長鍵列問題你會有更好的想法。
感謝關注!
新聞熱點
疑難解答