如何通过删除执行计划中的排序操作符优化SQL查询?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (22)

我刚刚开始研究如何通过索引优化查询,因为SQL数据正在快速增长。我查看了优化器是如何通过SSMS中的执行计划处理我的查询的,并注意到正在使用一个排序操作符。我听说一个排序操作符表示查询中的错误设计,因为排序可以通过索引过早地完成。下面是一个示例表和数据,与我所做的类似:

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])

我从简单的谓词开始。

[ParentStoreId] = 10
AND ([Type] = 0 OR [Type] = 1)

然后添加[Phone]列表示订单,以覆盖选择的输出。

因此,即使在构建索引时,优化器仍然使用排序运算符(而不是索引排序),因为[Phone]按顺序排序[ParentStoreId][Type]...。如果我移除[Type]列并运行查询:

SELECT [Phone]
FROM [dbo].[Store]
WHERE [ParentStoreId] = 10
--AND ([Type] = 0 OR [Type] = 1)
ORDER BY [Phone]

因此,问题是如何创建覆盖查询的索引(包括[Type]而不是让优化器使用排序?

我正在使用的表有超过2000万行

提问于
用户回答回答于

如果您仍然想要去掉这个类型的操作符,您可以尝试:

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]

UNION 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])

并对应用程序服务器上的两个列表进行排序,您可以在其中合并(如合并排序)预置列表,从而避免进行完整的排序。

扫码关注云+社区