4

我有一些带有一些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 秒内执行。

我注意到查询计划的差异。第一个查询的计划由两部分组成(一个用于空检查,一个用于 in 子句),然后是连接。而第二个计划只是索引搜索。

有什么方法可以改进我的参数化查询以更快地执行?

PS 这只是示例提炼查询,我想知道这in (select id from @p1)部分是否有任何不正确之处。

4

1 回答 1

5

几个建议:

  1. 不要使用SELECT *- 只需列出您实际需要的列

  2. 始终使用模式前缀

  3. 使用EXISTS而不是IN(因为前者可以短路):

    SELECT cols FROM dbo.SomeTable AS s 
      WHERE EXISTS (SELECT 1 FROM @p1 WHERE ID = s.SomeForeignId)
      OR SomeForeignId IS NULL;
    
  4. 上面的内容可能仍然以连接结束(本质上意味着 a 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- 不仅仅是一个外键约束,而是一个实际的非聚集索引。您的问题不清楚这是您寻求的索引。

于 2013-04-16T11:37:10.157 回答