我有一些IN
子句的SQL查询。为了改进查询计划缓存,我决定使用表值参数。
以下是示例WHERE ID IN (SELECT ID FROM @P1)
。
@ P1是以下类型的变量:
CREATE TYPE [dbo].[Ids] AS TABLE(
[ID] [int] NOT NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
但我注意到有些查询会变慢。 这是查询示例:
select * from SomeTable s where ((s.SomeForeignId in (select id from @p1)) or s.SomeForeignId is null)
在我的数据库上以2.1秒的速度执行。
旧查询:
select * from SomeTable s where ((s.SomeForeignId in (1,2,3.....)) or s.SomeForeignId is null)
在1.8秒内完成。
我注意到查询计划的不同之处。第一个查询的计划由2部分组成(一个用于空检查,一个用于in子句)然后是连接。而第二个计划只是索引寻求。
有什么方法可以改善我的参数化查询以更快地执行?
P.S。这只是示例提取的查询,我想知道这个in (select id from @p1)
部分是否有任何错误。
答案 0 :(得分:5)
一些建议:
SELECT *
- just list the columns you actually need。使用EXISTS
而不是IN
(因为前者可能会短路):
SELECT cols FROM dbo.SomeTable AS s
WHERE EXISTS (SELECT 1 FROM @p1 WHERE ID = s.SomeForeignId)
OR SomeForeignId IS NULL;
以上内容可能最终会以连接(实际上意味着UNION
)结束,但您可以尝试编写自己的UNION ALL
以避免OR
:
SELECT cols FROM dbo.SomeTable AS s
WHERE EXISTS (SELECT 1 FROM @p1 WHERE ID = s.SomeForeignId)
UNION ALL
SELECT cols FROM dbo.SomeTable
WHERE SomeForeignId IS NULL;
令我感到不安的是,您现有的任何一种变化都需要几乎两秒钟。请确保SomeTable.SomeForeignId
上有索引 - 不仅是外键约束,而是实际的非聚簇索引。你的问题并不清楚这是你寻求的指数。