我想计算所有不紧急且订单状态 = 1(已发货)的订单。
这应该是一个非常简单的优化查询。我想在 Orders 表上放置一个简单的过滤索引来覆盖这个查询,使其成为一个恒定的时间/O(1) 操作。但是,当我查看查询计划时,它似乎使用了没有意义的索引扫描。理想情况下,此查询应该只返回索引中的项目数。
该表如下所示(简化为本质):
CREATE TABLE [dbo].[Orders](
[Id] [int] IDENTITY(1,1) NOT NULL,
[IsUrgent] [bit] NOT NULL,
[Status] [tinyint] NOT NULL
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED ( [Id] ASC )
我创建了这个过滤索引:
CREATE INDEX IX_Orders_ShippedNonUrgent ON Orders(Id) WHERE IsUrgent = 0 AND Status = 1;
现在,当我执行此查询时:
SELECT COUNT(*) FROM Orders WHERE IsUrgent = 0 AND Status = 1
我看到查询计划正在使用 IX_Orders_ShippedNonUrgent,但它正在执行索引扫描并在约 150,000 行订单中执行大约 200 次读取。
假设过滤的索引保持最新,是否可以始终让此查询在恒定时间内运行?理想情况下,它应该只执行 1 次读取来获取索引的大小。
如果我切换到这样的非过滤索引:
CREATE INDEX IX_Orders_IsUrgentStatus ON Orders(IsUrgent, Status);
查询计划使用 Index Seek,但仍然执行比回答这个简单查询所需的更多的读取。
更新
我能够做到这一点
SELECT TOP 1 rows FROM sys.partitions p
INNER JOIN sys.indexes i
ON i.name = 'IX_Orders_ShippedNonUrgent'
AND i.object_id = p.object_id
AND i.index_id = p.index_id
并在 9 次读取中获得结果,但似乎应该有一种更简单、更简单的方式来使用简单的 COUNT(*) 查询。