有沒有覺得這個基數很熟悉,沒錯,在執行計畫裡,我們可以把每個運算子的估計的資料列數目當作是基數喔
有時查詢最佳化工具沒法正確的預估基數,使得執行計畫的成本估計不正確,會導致選擇次佳的執行計畫呢
BOL查詢效能不佳的疑難排解:基數估計裡提到,查詢最佳化工具根據兩個主要因數來判斷執行查詢計畫的成本,基數就是其中的一個因數喔
如果改善基數,便能產生更好的估計成本,進而可有更快的執行計畫。
這麼重要的基數,難道不值得花一點時間來了解一下呢!所以我們來看一個使用計算欄位來改善基數的例子!
執行以下查詢,然後檢查一下執行計畫
USE AdventureWorks2008R2
執行以下查詢,然後檢查一下執行計畫
USE AdventureWorks2008R2
GO
--
SELECT * FROM Sales.SalesOrderDetail
WHERE OrderQty * UnitPrice > 27000
GO
接著我們使用以下兩個查詢來看有哪些統計資料,第一個查詢可以看出欄位對應,第二個查詢可以看出建立順序,愈後面的建立時間點愈近
執行計畫如上圖,那我們直接看篩選運算子的內容(如下圖),估計的資料列數目是總筆數121317的30%,也就是36395.1筆,而實際的資料列數目才3筆,差距如此之大表示查詢最佳化工具無法依據OrderQty * UnitPrice > 27000述詞來做預估,只好用猜的,因為是>,所以才會用30%,怎麼猜的我在前一篇密度有提到
EXEC sp_helpstats 'Sales.SalesOrderDetail','ALL'
GO
SELECT * FROM sys.stats
WHERE OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail')
ALTER TABLE Sales.SalesOrderDetail
ADD cc AS OrderQty * UnitPrice
GO
再次檢查統計資料,還是6筆,因為建立計算欄位並不會自動建立統計資料,統計資料是在第一次執行時才會建立的
再次檢查統計資料,還是6筆,因為建立計算欄位並不會自動建立統計資料,統計資料是在第一次執行時才會建立的
EXEC sp_helpstats 'Sales.SalesOrderDetail','ALL'
GO
SELECT * FROM sys.stats
WHERE OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail')
接著再執行一次以下查詢,並檢查執行計畫
SELECT * FROM Sales.SalesOrderDetail
WHERE OrderQty * UnitPrice > 27000
從下圖你應該可以注意到估計的資料列數目比起之前精準許多了,從36395.1降為25.8132,使用計算欄位在這情況是可以改善基數估計的喔,不過因為沒有可用的索引,所以看不出執行計畫成本有何改善,相信你也發現上圖有出現遺漏索引的提示了,告訴我們建立索引可影響53.2217的成本呢,遺漏索引是一個輕量型的工具,實務上大部分還是會使用使用 Database Engine Tuning Advisor 來微調索引組態
從下圖你應該可以注意到估計的資料列數目比起之前精準許多了,從36395.1降為25.8132,使用計算欄位在這情況是可以改善基數估計的喔,不過因為沒有可用的索引,所以看不出執行計畫成本有何改善,相信你也發現上圖有出現遺漏索引的提示了,告訴我們建立索引可影響53.2217的成本呢,遺漏索引是一個輕量型的工具,實務上大部分還是會使用使用 Database Engine Tuning Advisor 來微調索引組態
EXEC sp_helpstats 'Sales.SalesOrderDetail','ALL'
GO
SELECT * FROM sys.stats
WHERE OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail')
接著建立計算欄位的索引來看看,是不是能幫助查詢最佳化工具透過使用索引而產生更好的執行計畫呢?
CREATE INDEX IX_cc ON Sales.SalesOrderDetail(cc)
GO
再檢查一下統計資料,你會發現已自動建立的索引IX_cc的統計資料了
再檢查一下統計資料,你會發現已自動建立的索引IX_cc的統計資料了
EXEC sp_helpstats 'Sales.SalesOrderDetail','ALL'
GO
SELECT * FROM sys.stats
WHERE OBJECT_ID = OBJECT_ID('Sales.SalesOrderDetail')
再執行一次查詢吧,你會發現執行計畫選擇索引搜尋及索引鍵查閱來查閱囉
SELECT * FROM Sales.SalesOrderDetail
WHERE OrderQty * UnitPrice > 27000
--最後記得還原喔
DROP INDEX Sales.SalesOrderDetail.IX_cc
GO
ALTER TABLE Sales.SalesOrderDetail DROP COLUMN cc
GO
0 意見:
張貼留言