由于 WHERE 子句中有超过 100,000 个条目,SQL Server 错误 8632

Dom*_*que 16 sql-server configuration limits

我的问题(或至少是错误消息)与查询处理器耗尽内部资源非常相似- 非常长的 sql query

我的客户正在使用 SQL 选择查询,其中包含一个恰好包含 100,000 个条目的 where 子句。

查询失败,错误 8632 和错误消息

内部错误:已达到表达式服务限制。请在您的查询中寻找潜在的复杂表达式,并尝试简化它们。)

我发现抛出此错误消息非常奇怪,正好是 100,000 个条目,所以我想知道这是否是一个可配置的值。是这种情况吗?如果是,我怎样才能将此值增加到更高的值?

MSDN 上,有人提议重新编写查询,但我想避免这种情况。

同时我发现我正在谈论的条目列表包含自然数,其中相当一部分似乎是连续的(例如 (1,2,3,6,7,8,9,10,12, 13、15、16、17、18、19、20)。

这使得 SQL where 子句类似于:

where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)
Run Code Online (Sandbox Code Playgroud)

我可以将其转换为:

where (entry between 1 and 3) OR
      (entry between 6 and 10) OR
      (entry between 12 and 13) OR
      (entry between 15 and 20)
Run Code Online (Sandbox Code Playgroud)

可以通过以下方式缩短:

where entry in (1,...,3,6,...,10,12,13,15,...,20)
Run Code Online (Sandbox Code Playgroud)

......或类似的东西?(我知道这是一个长镜头,但它会使软件更新更容易和更易读)

供您参考: where 子句中的数据是在另一个表上完成的计算结果:首先在开始时读取并过滤该表的条目,然后进行一些额外的处理(这是不可能使用的SQL),额外处理的结果是更多的过滤,并且结果用于 where 子句中。由于无法在 SQL 中编写完整的过滤,因此使用了上述方法。显然, where 子句的内容可能会在每次处理时发生变化,因此需要动态解决方案。

Bre*_*zar 68

要搜索超过 100,000 个值,请将它们放在临时表中,您要搜索的每个值占一行。然后,将您的查询加入该临时表以进行过滤。

超过 100,000 个值的东西不是参数 - 它是一个表格。与其考虑提高限制,不如考虑Swart 的 10% 规则:如果您接近 SQL Server 限制的 10%,您可能会过得很糟糕。


Aar*_*and 10

如果您无论如何要更改应用程序,请考虑

(a) 对整个值集使用 TVP - 您将DataTable在 C# 中创建 a并使用 将其传递到存储过程中StructuredType,正如我在此处演示的那样。(希望 100,000 个条目是不正常的,因为无论您使用什么方法,可扩展性都可能是一个问题。)

CREATE TYPE dbo.optionA AS TABLE(value int PRIMARY KEY);
GO

CREATE PROCEDURE dbo.procedure_optionA
  @t dbo.optionA READONLY
AS
BEGIN
  SET NOCOUNT ON;
  SELECT <cols> FROM dbo.<table> AS t
    INNER JOIN @t AS tvp
    ON t.entry = tvp.value;
END
GO
Run Code Online (Sandbox Code Playgroud)

或者

(b) 使用 TVP 传入范围的上限和下限,并编写略有不同的连接(感谢 @ypercube)。

  CREATE TYPE dbo.optionB AS TABLE
  (
    LowerBound int,
    UpperBound int,
    PRIMARY KEY (LowerBound, UpperBound)
  );
  GO

  CREATE PROCEDURE dbo.procedure_optionB
    @t dbo.OptionB READONLY
  AS
  BEGIN
    SET NOCOUNT ON;
    SELECT <cols> FROM dbo.<table> AS t
      INNER JOIN @t AS tvp
      ON  t.entry >= tvp.LowerBound 
      AND t.entry <= tvp.UpperBound;
  END
  GO
Run Code Online (Sandbox Code Playgroud)


Sql*_*ide 6

不,它是不可配置的,您不能将其增加到更高的级别。

您提到的 MSDN 文章和其他文章中建议了解决方法。我在这里提到了两个,但您可以搜索更多。


Zep*_*hyr 6

只是我的 2\xc2\xa2 关于缩短查询条件的问题:-

\n\n

如果您能够entry提前确定 的所有可能值,那么采用查询的补集是否可行?

\n\n

\n\n
where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
where entry not in (4,5,11,14)\n
Run Code Online (Sandbox Code Playgroud)\n