如何在T-SQL中使用一个变量和多个常量优化条件

如何在T-SQL中使用一个变量和多个常量优化条件,sql,sql-server,optimization,where-clause,Sql,Sql Server,Optimization,Where Clause,我在T-SQL中有一个简单的查询: SELECT * FROM Table t WHERE t.Column IN ( 'Value1', 'Value2', 'Value3', ..., 'ValueN' ) ; 当然,通过几个连接和子查询,查询实际上要复杂得多,但目前这并不重要 问题是: 以下哪项性能更快 (1) 原始状态 t.Column IN ( 'Value1', 'Value2', 'Value3', ..., 'ValueN' ) (2) 使用仅包含一个名为Valu

我在T-SQL中有一个简单的查询:

SELECT
  *
FROM
  Table t
WHERE
  t.Column IN ( 'Value1', 'Value2', 'Value3', ..., 'ValueN' )
;
当然,通过几个连接和子查询,查询实际上要复杂得多,但目前这并不重要

问题是: 以下哪项性能更快

(1) 原始状态

t.Column IN ( 'Value1', 'Value2', 'Value3', ..., 'ValueN' )
(2) 使用仅包含一个名为Value的列(可能是主键)的表ValueEnumeration,该表将填充值“Value1”、“Value2”

SELECT
  *
FROM
  Table t
WHERE
  t.Column in ( SELECT ve.Value FROM ValueEnumeration ve )
;
(3) 使用用户定义函数(UDF),一个精确的标量函数,称为IsAllowedValue

职能:

CREATE FUNCTION dbo.IsAllowedValue ( @ValueToCheck VARCHAR(20) ) RETURNS INT
AS
BEGIN
  IF @ValueToCheck = 'Value1'
     OR @ValueToCheck = 'Value2'
     OR @ValueToCheck = 'Value3'
     ...
     OR @ValueToCheck = 'ValueN'
  BEGIN
    RETURN 1;
  END;
  RETURN 0;
END
;
查询:

SELECT
  *
FROM
  Table t
WHERE
  dbo.IsAllowedValue(t.Column) = 1
;
嗯,我想第一个是最快的解决办法。但是,我需要在存储过程的许多地方执行类似的检查。一旦值的原始枚举在将来发生更改(这很可能发生-例如,必须向其添加新值),您将必须转到代码中所有出现的原始条件,并在其中添加新值。因此,我决定采用一种更可重用的解决方案。但我不知道该选哪一个。有时我需要以另一种方式进行测试(
其中t.Column不在(…)
)。我还想到在
内部联接
(用于肯定检查)或
左侧外部联接
(用于否定检查)中使用表ValueEnumeration,但这将很难实现,因为我在代码中有大约50个这样的条件位置,而且通常,添加连接会显著改变SQL查询的外观和执行计划,后者并不总是好的


您知道吗?

只要在调用查询之前存储允许的值,解决方案2就可以了。这不会影响您的性能(您将一次性获得值,而不是针对表中的每个记录),并且比解决方案1更具可重用性

declare @AllowedValues table(val varchar(...))

insert into @AllowedValues 
SELECT ve.Value FROM ValueEnumeration ve
然后您可以在代码中使用它:

......
WHERE
  t.Column in ( SELECT val FROM @AllowedValues )

我最终决定采用第三种(通常不推荐)解决方案(创建UDF)。就性能而言,似乎还可以。或者,至少它不比第二种解决方案慢(一个“允许”值表)

函数虽然通常被认为是许多SQL查询的瓶颈,但它有两个优点:

(i) 它是可重用的,并且易于调整(例如,如果将来必须添加一些新值)

(ii)与枚举值表不同,每当您看到函数的DDL、函数定义时,您都可以查看当前使用的值(常量)(尽管第一种解决方案的优点是不可重复使用)。如果使用表,则必须执行SELECT以检查当前存在的值

(iii)即使在句法上,写作也更容易

dbo.IsAllowedValue(t.Column) = 1


如果将来我遇到任何不好/好的体验,我会提供更多关于这个主题的评论。

我认为2将是
n>20
最快的,3将是最慢的(因为函数速度慢,需要全表扫描)。尽管如此,关于性能的声明本身是有缺陷的,我建议您自己检查一下。。直观地说,从可读性和性能的角度来看,第一个选项是最好的bot。@Ginden我目前在ValueEnumeration表中有大约15个值。谢谢你的评论。你是对的。我必须自己尝试所有选项…您是否在
上有
索引
?Jan,您的语法
t.column(@AllowedValues)
不适用于t-SQL(必须声明标量变量“@AllowedValues”)。你的意思是
t.Column(从@AllowedValues中选择val)
?好的,谢谢。但是我看不出
从@AllowedValues中选择val
从ValueEnumeration中选择Value
之间的区别。您是否认为具有几个值(<20行)的表变量比普通表的性能更好?是的,我认为。我现在不可能仔细地测试它,但是看看那里的例子
t.Column IN (SELECT Value FROM ValueEnumeration)