IN过滤器可以处理的内容有没有限制?例如:
SELECT Name
FROM People
WHERE Job IN (All the values goes here)
Run Code Online (Sandbox Code Playgroud)
IN 的Microsoft 文档说:
“在括号内显式包含大量值(以逗号分隔的数千个值),在 IN 子句中会消耗资源并返回错误 8623 或 8632。要解决此问题,请将 IN 列表中的项目存储在一个表,并在 IN 子句中使用 SELECT 子查询。”
但是否有任何确切或近似的数字
数以千计的值
Aar*_*and 12
这取决于。严重地。这就是为什么文档不能具体说明您会注意到环境退化的地方。
解决方案是停止这样做(并担心它)并使用表值参数。
如果您在 C# 中有这样的值,您可以将逗号分隔的列表构建为字符串以在查询中连接在一起,那么您在 C# 中的值是这样的,您可以将它们填充到 DataTable 或其他结构(也许这就是它们最初来自的地方),并将该结构作为参数传递给存储过程。
严格来说,您可以保证查询失败并显示 65536 个值。话虽如此,我认为在实践中将 32768 视为上限是相当安全的,但这并不是最小的上限。最小上限取决于查询中发生的其他事情和其他本地因素。你可以通过一个简单的例子看到这一点。首先将 100k 行放入堆中:
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);
Run Code Online (Sandbox Code Playgroud)
假设我想在 IN 子句中放入 32768 个值以进行以下形式的查询:SELECT COUNT(*) FROM dbo.Q228695 WHERE ID IN ();
这在 SQL 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);
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
消息 8632,级别 17,状态 2,第 1 行
内部错误:已达到表达式服务限制。请在您的查询中寻找潜在的复杂表达式,并尝试简化它们。
如果我从IN
子句中删除一个值,查询将在 24 秒后成功。对于这个非常简单的查询,32767 是仍允许执行查询的最大值数。请注意,有关错误 8632 的 Microsoft 文档说明如下:
出现此问题的原因是 SQL 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
);
Run Code Online (Sandbox Code Playgroud)
即使您的查询没有抛出错误,一旦将太多值放入IN
子句中,您也会付出沉重的性能代价。
归档时间: |
|
查看次数: |
12189 次 |
最近记录: |