对于IN过滤器可以处理的内容有任何限制吗?例如:
SELECT Name
FROM People
WHERE Job IN (All the values goes here)
微软的在……里面文档说:
“在括号中显式包含大量值(以逗号分隔的值),在in子句中可以使用资源并返回错误8623或8632。要解决此问题,请将项存储在一个表中的IN列表中,并在in子句中使用SELECT子查询。”
但是是否有确切的或近似的数字
成千上万的价值
发布于 2019-02-01 15:43:13
那得看情况。我是认真的。这就是为什么文档不能具体说明在什么地方会注意到环境中的退化。
解决方案是停止这样做(并且担心它),而使用表值参数。
如果使用C#中的值,可以将逗号分隔的列表构建为字符串,以便在查询中连接在一起,则可以将C#中的值填充到DataTable或其他结构中(可能这是它们最初的来源),并将该结构作为参数传递给存储过程。
发布于 2019-02-06 02:16:29
严格地说,您可以保证查询失败的值为65536。尽管如此,我认为在实践中考虑32768作为上限是相当安全的,但它并不是最小的上限。最小上限取决于查询中还发生了什么以及其他本地因素。您可以通过一个简单的例子看到这一点。首先,将100 k行放入堆中:
DROP TABLE IF EXISTS dbo.Q228695;
CREATE TABLE dbo.Q228695 (ID BIGINT);
INSERT INTO dbo.Q228695 WITH (TABLOCK)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);
假设我想为以下形式的查询在in子句中放置32768个值:SELECT COUNT(*) FROM dbo.Q228695 WHERE ID IN ();
,在Server 2017中使用STRING_AGG
很容易做到这一点:
DECLARE @nou VARCHAR(MAX);
SELECT @nou = 'SELECT COUNT(*) FROM dbo.Q228695 WHERE ID IN (' + STRING_AGG(CAST(RN AS VARCHAR(MAX)), ',') + ')'
FROM
(
SELECT TOP (32768) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) q
OPTION (MAXDOP 1);
EXEC (@nou);
我得到以下错误:
Msg 8632,级别17,状态2,第1行内部错误:已达到表达式服务限制。请在查询中查找潜在的复杂表达式,并尝试简化它们。
如果从IN
子句中删除一个值,查询将在24秒后成功。对于这个非常简单的查询,32767是允许执行查询的最大值数。请注意,微软关于错误8632的文档表示如下:
发生此问题是因为Server限制了可以包含在查询的单个表达式中的标识符和常量的数量。这一限额为65,535。
32767有效,32768无效。我不认为65535/2 = 32767.5不是巧合。无论出于什么原因,观察到的行为是,IN
子句中的每个常量都是接近极限的两个常数。
我认为这是一个错误的问题。如果我将这些相同的值放入临时表中,则查询将在0秒钟内执行:
DROP TABLE IF EXISTS #t;
CREATE TABLE #t (ID BIGINT);
INSERT INTO #t WITH (TABLOCK)
SELECT TOP (32768) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);
SELECT COUNT(*)
FROM dbo.Q228695
WHERE ID IN (
SELECT t.ID
FROM #t t
);
即使您的查询没有抛出错误,一旦您在IN
子句中添加了太多的值,也会付出沉重的性能代价。
https://dba.stackexchange.com/questions/228695
复制相似问题