通過在執行計劃中刪除排序運算子來優化SQL查詢
我剛剛開始研究通過索引優化我的查詢,因為SQL資料越來越大而且快速.我查看了優化器如何通過SSMS中的執行計劃處理我的查詢,並注意到正在使用Sort運算子.我聽說排序運算子表示查詢中的錯誤設計,因為可以通過索引過早排序.所以這裡是一個示例表和資料類似於我在做什麼:
IF OBJECT_ID('dbo.Store') IS NOT NULL DROP TABLE dbo.[Store] GO CREATE TABLE dbo.[Store] ( [StoreId] int NOT NULL IDENTITY (1, 1), [ParentStoreId] int NULL, [Type] int NULL, [Phone] char(10) NULL, PRIMARY KEY ([StoreId]) ) INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 0, '2223334444') INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 0, '3334445555') INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 1, '0001112222') INSERT INTO dbo.[Store] ([ParentStoreId], [Type], [Phone]) VALUES (10, 1, '1112223333') GO
這是一個示例查詢:
SELECT [Phone] FROM [dbo].[Store] WHERE [ParentStoreId] = 10 AND ([Type] = 0 OR [Type] = 1) ORDER BY [Phone]
我建立一個非聚簇索引以幫助加快查詢速度:
CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Type], [Phone])
要構建IX_Store索引,我從簡單的謂詞開始
[ParentStoreId] = 10 AND ([Type] = 0 OR [Type] = 1)
然後我新增ORDER BY的[Phone]列並覆蓋SELECT輸出
因此,即使構建索引,優化器仍然使用Sort運算子(而不是索引排序),因為[Phone]在[ParentStoreId] AND [Type]之後排序.如果我從索引中刪除[Type]列,並執行查詢:
SELECT [Phone] FROM [dbo].[Store] WHERE [ParentStoreId] = 10 --AND ([Type] = 0 OR [Type] = 1) ORDER BY [Phone]
那麼當然,優化器不使用Sort運算子,因為[Phone]按[ParentStoreId]排序.
所以問題是如何建立一個覆蓋查詢的索引(包括[Type]謂詞),而沒有優化器使用Sort?
編輯:
我正在使用的表有超過2000萬行
首先,您應該驗證排序實際上是一個性能瓶頸.排序的持續時間將取決於要排序的元素的數量,並且特定父儲存的儲存數量可能很小. (這是假定在應用where子句後應用了sort運算子).
I’ve heard that a Sort operator indicates a bad design in the query since the sort can be made prematurely through an index
這是一個過度泛化.通常,排序運算子可以平均移動到索引中,並且如果僅獲取結果集的前幾行,則可以顯著降低查詢成本,因為資料庫不再需要獲取所有匹配的行(並對它們進行排序所有)找到第一個,但可以讀取結果集順序的記錄,並停止一次足夠的記錄被找到.
在你的情況下,你似乎正在獲取整個結果集,所以排序不太可能使事情變得更糟(除非結果集是巨大的).另外,在你的情況下,構建一個有用的排序索引可能不是微不足道的,因為where子句包含一個或.
現在,如果你還想擺脫那個排序運算子,你可以嘗試:
SELECT [Phone] FROM [dbo].[Store] WHERE [ParentStoreId] = 10 AND [Type] in (0, 1) ORDER BY [Phone]
或者,您可以嘗試以下索引:
CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Phone], [Type])
嘗試讓查詢優化器僅在ParentStoreId上進行索引範圍掃描,然後掃描索引中的所有匹配行,如果型別匹配則輸出它們.但是,這可能會導致更多的磁碟I / O,因此減慢了查詢速度,而不是加快速度.
編輯:作為最後的手段,您可以使用
SELECT [Phone] FROM [dbo].[Store] WHERE [ParentStoreId] = 10 AND [Type] = 0 ORDER BY [Phone] UIO/">NION ALL SELECT [Phone] FROM [dbo].[Store] WHERE [ParentStoreId] = 10 AND [Type] = 1 ORDER BY [Phone]
同
CREATE NONCLUSTERED INDEX IX_Store ON dbo.[Store]([ParentStoreId], [Type], [Phone])
並對應用伺服器上的兩個列表進行排序,您可以在其中合併(如合併排序)預分類列表,從而避免完整排序.但是,這真的是一個微型優化,儘管加速排序本身一個數量級,但不太可能影響查詢的總執行時間,因為我預計瓶頸是網路和磁碟I / O,特別是考慮到由於索引未聚集,磁碟將執行大量的隨機訪問.
程式碼日誌版權宣告:
翻譯自:http://stackoverflow.com/questions/6001197/optimizing-sql-queries-by-removing-sort-operator-in-execution-plan