【问题标题】:How to optimize a condition with a variable and multiple constants in T-SQL如何在 T-SQL 中使用变量和多个常量优化条件
【发布时间】:2026-01-25 22:30:02
【问题描述】:

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

SELECT
  *
FROM
  Table t
WHERE
  t.Column IN ( 'Value1', 'Value2', 'Value3', ..., 'ValueN' )
;

当然,查询实际上要复杂得多,有几个 JOIN 和子查询,但目前这无关紧要。

问题是: 以下哪项在性能方面更快?

(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
;

嗯,我想第一个将是最快的解决方案。但是,我需要在存储过程的许多地方执行类似的检查。一旦值的原始枚举在未来发生变化(这很可能发生 - 例如,必须向其中添加一个新值),您将必须转到代码中原始条件的所有出现并添加新的那里的价值。因此,我决定采用更可重用的解决方案。但我不知道该选择哪一个。我有时需要反过来做一个测试(WHERE t.Column NOT IN (...))。我还想到在INNER JOIN(用于肯定检查)或LEFT OUTER JOIN(用于否定检查)中使用表ValueEnumeration,但这实施起来会很痛苦,因为我有大约。代码中有 50 个此类条件的位置,一般来说,添加 JOIN 会极大地改变 SQL 查询的外观以及执行计划,后者并不总是好的。

你有什么想法吗?

【问题讨论】:

  • 我想n > 20 2 最快,3 最慢(因为函数很慢并且需要全表扫描)。虽然 - 关于性能的声明本质上是有缺陷的,我建议您自己检查一下。
  • Race your horses.。直观地说,从可读性和性能的角度来看,第一个选项是最好的机器人。
  • @Ginden 我目前在 ValueEnumeration 表中有大约 15 个值。谢谢你的评论。你是对的。我将不得不自己尝试所有选项...
  • 你在column上有一个INDEX吗?

标签: sql sql-server optimization where-clause


【解决方案1】:

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

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

insert into @AllowedValues 
SELECT ve.Value FROM ValueEnumeration ve

然后你可以在你的代码中使用它:

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

【讨论】:

  • Jan,您的语法 t.Column in ( @AllowedValues ) 不适用于 T-SQL(必须声明标量变量“@AllowedValues”)。你是说t.Column in ( SELECT val FROM @AllowedValues ) 吗?
  • 好的,谢谢。但我看不出SELECT val FROM @AllowedValuesSELECT Value FROM ValueEnumeration 之间的区别。您是否认为具有几个值(
  • 是的,我愿意。我现在没有可能仔细测试它,但是看看那里,例如*.com/questions/11857789/…
【解决方案2】:

好吧,我最终决定采用第三种(通常不推荐)解决方案(创建 UDF)。似乎没问题。在性能方面。或者,至少,它不比第二种解决方案(“允许”值的表)慢。

一个函数,虽然通常被认为是许多 SQL 查询的瓶颈,但它提供了几个优点:

(i) 可重复使用且易于调整(例如,如果将来必须添加一些新值)。

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

(iii) 即使在语法上,它也更容易编写

dbo.IsAllowedValue(t.Column) = 1

t.Column IN (SELECT Value FROM ValueEnumeration)

如果以后有任何不好/好的经验,我会提供更多关于该主题的 cmet。

【讨论】:

    最近更新 更多