我有一个电子邮件发送表,需要保存超过400万行。一个特定的报告也需要参考这个表来产生一些统计数据,并且它比我想要的运行时间更长(目前大约30秒)。
我已经检查了估计的执行计划,该计划显示94%的成本是由单个谓词引起的(如果我正确地解释了这一点)。
请注意,以下示例显示了小片段以保持简洁。其他索引针对其他查询。
谓词:
[EmsDb].[dbo].[MailDispatchPending].[MailCampaignId]=[@MailCampaignId] OR [@MailCampaignId] IS NULL
我相信这是指向以下SQL:
WHERE @MailCampaignId IS NULL OR MailCampaignId = @MailCampaignId -- Restrict to mail campaign where parameter passed
我试图通过测试以下索引来提高性能。既不会影响执行计划输出,也不会提高查询速度。
/****** Object: Index [IX_MailCampaignId] Script Date: 11/27/2013 11:21:00 ******/
CREATE NONCLUSTERED INDEX [IX_MailCampaignId] ON [dbo].[MailDispatchPending]
(
[MailCampaignId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object: Index [IX_MailCampaignId] Script Date: 11/27/2013 11:21:00 ******/
CREATE NONCLUSTERED INDEX [IX_MailCampaignId] ON [dbo].[MailDispatchPending]
(
[Id] ASC,
[MailCampaignId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
有人可以建议更好的索引类型或不同的策略来帮助我提高绩效吗?
答案 0 :(得分:3)
不要使用这种方法:
WHERE @MailCampaignId IS NULL OR MailCampaignId = @MailCampaignId
改为使用:
IF @MailCampaignId IS NULL
BEGIN
SELECT ..
FROM ...
END
ELSE
BEGIN
SELECT ..
FROM ...
WHERE MailCampaignId = @MailCampaignId
END
它可能感觉更多工作,但SQL-Server使用缓存的执行计划,除非您强制重新编译,否则它将使用相同的执行计划,无论参数是否为null。如果使用上述方法,则可以保证使用正确的计划,具体取决于参数是否为空
答案 1 :(得分:2)
IS NULL OR
部分会影响你的表现,因为如果输入为NULL,你就会要求每一行都是扫描。
如果可能的话,我会删除那个部分,看看是否有帮助,如果不可能,那么我会重新考虑我何时需要所有这些并考虑替代方法,例如多个查询而不是一个甚至是存储变化。
答案 2 :(得分:0)
这可能是@GarethD提出的替代解决方案吗?
WHERE MailCampaignId = COALESCE(@MailCampaignId,MailCampaignId)