我的桌子是这样的:
CREATE TABLE [dbo].[ClosedTaskCustomFields](
[ClosedTaskId] [uniqueidentifier] NOT NULL,
[CustomFieldId] [uniqueidentifier] NOT NULL,
[Value] [nvarchar](450) NULL
...
CONSTRAINT [PK_ClosedTaskCustomFields] PRIMARY KEY CLUSTERED
(
[ClosedTaskId] ASC,
[CustomFieldId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
我也有这样的索引用于连接 ClosedTask 表:
CREATE NONCLUSTERED INDEX [IX_ClosedTaskCustomFields_ClosedTaskId] ON [dbo].[ClosedTaskCustomFields]
(
[ClosedTaskId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
但我不明白为什么这样的查询会读取所有 ClosedTaskCustomFields 表以加入 ClosedTask(如果我有索引)。
select count(1) from ClosedTaskCustomFields ctcf
join ClosedTask c on c.id = ctcf.ClosedTaskId
where c.State = 'Rejected'
-- Result count is 50k.
SQL Server 根据其估计选择看起来最便宜的计划。这意味着您想要的计划(在两个表上都进行索引查找)的成本会更高。您可以使用提示自行测试这一点
FORCESEEK
。请注意,较高的估计成本并不一定意味着该计划的执行速度会比在特定硬件上选择的替代方案慢。
该计划成本较低的原因有很多:
您可能会发现优化器自然会选择带有提示的搜索计划
MAXDOP 1
,或者通常会选择更高的并行成本阈值。似乎您已将其设置为默认值 5,如今许多人认为该值太低了。否则,您只能使用常规方法来覆盖优化器选择 - 使用诸如 之类的提示
FORCESEEK
。除非查询至关重要并且节省几毫秒的时间很重要,否则我不会打扰。有关行模式位图的更多信息,请参阅我的文章Bitmap Magic(或者……SQL Server 如何使用位图过滤器)。
ClosedTask
SQL-Server 在索引上使用了索引查找State
(可能是因为在条件中使用了该列)和在 上进行了索引扫描ClosedTaskCustomFields
。如果
State
选择性很强,那么此查询将仅选择每个表中记录的一小部分。但可能不是,因为你只有几个州。因此,与查找相比,仅对自定义字段表中的索引进行扫描并跳过相对较少数量的不匹配记录很可能更便宜。索引查找需要多次磁盘访问才能深入索引树。所以,它不一定便宜。State
如果选择性很强,即如果有很多州,情况就会有所不同。但这只是一个假设,因为我不知道查询优化器使用的算法。