in子句的表值参数比simple in子句慢

时间:2013-04-16 11:06:45

标签: sql sql-server table-valued-parameters

我有一些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)部分是否有任何错误。

1 个答案:

答案 0 :(得分:5)

一些建议:

  1. Don't use SELECT * - just list the columns you actually need
  2. Use the schema prefix always
  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. 以上内容可能最终会以连接(实际上意味着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;
    
  5. 令我感到不安的是,您现有的任何一种变化都需要几乎两秒钟。请确保SomeTable.SomeForeignId上有索引 - 不仅是外键约束,而是实际的非聚簇索引。你的问题并不清楚这是你寻求的指数。