gpt4 book ai didi

sql - 通过删除执行计划中的排序运算符来优化 SQL 查询

转载 作者:太空狗 更新时间:2023-10-30 01:40:01 24 4
gpt4 key购买 nike

我刚刚开始考虑通过索引优化我的查询,因为 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])

为了构建 IX_Store 索引,我从简单的谓词开始

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

然后我为 ORDER BY 添加 [Phone] 列并覆盖 SELECT 输出

因此即使建立了索引,优化器仍然使用排序运算符(而不是索引排序),因为 [Phone] 是在 [ParentStoreId] AND 之后排序的[类型]。如果我从索引中删除 [Type] 列并运行查询:

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

当然,优化器不会使用 Sort 运算符,因为 [Phone] 是按 [ParentStoreId] 排序的。

所以问题是我如何创建一个索引来覆盖查询(包括 [Type] 谓词)而不是让优化器使用排序?

编辑:

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

最佳答案

首先,您应该验证排序是否确实是性能瓶颈。排序的持续时间将取决于要排序的元素的数量,并且特定父存储的存储数量可能很小。 (假设在应用 where 子句之后应用了排序运算符)。

I’ve heard that a Sort operator indicates a bad design in the query since the sort can be made prematurely through an index

这是一种过度概括。通常,排序运算符可以很容易地移动到索引中,并且,如果只获取结果集的前几行,则可以大大降低查询成本,因为数据库不再需要获取所有匹配的行(并对它们进行排序) all) 找到第一个,但可以按结果集顺序读取记录,并在找到足够的记录后停止。

在您的情况下,您似乎正在获取整个结果集,因此排序不太可能使事情变得更糟(除非结果集很大)。此外,在您的情况下,构建有用的排序索引可能并非易事,因为 where 子句包含 or。

现在,如果您仍然想摆脱那个排序运算符,您可以尝试:

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 进行索引范围扫描,然后扫描索引中所有匹配的行,如果 Type 匹配则输出它们。但是,这可能会导致更多的磁盘 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])

并在应用程序服务器上对两个列表进行排序,您可以在其中合并(如合并排序)预排序的列表,从而避免完全排序。但这确实是一个微观优化,虽然将排序本身加快了一个数量级,但不太可能对查询的总执行时间产生太大影响,因为我预计瓶颈是网络和磁盘 I/O,特别是考虑到磁盘将进行大量随机访问,因为索引不是聚集的。

关于sql - 通过删除执行计划中的排序运算符来优化 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6001197/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com