超过192个参数的查询永远不会完成

时间:2013-07-10 16:21:33

标签: sql sql-server sql-server-2008 sql-server-2008-r2

对于好奇,我发现这个问题是因为Entity Framework生成的查询,但是我通过SSMS运行普通的SQL命令来重现它。

摘要:我正在运行一个简单查询,通过查询复合主键来检查现有数据。如果我运行具有193个或更多参数的查询的参数化版本,则查询永远不会完成(我在取消之前等待了5分钟)。如果我使用192或更少的参数运行类似的查询,它几乎立即完成,正如主键查找所期望的那样。

后台:我的下表带有群集复合主键:

CREATE TABLE MyTable {
    KeyCol1 INT NOT NULL,
    KeyCol2 INT NOT NULL,
    KeyCol3 INT NOT NULL,
    OtherCol1 INT NOT NULL,
    OtherCol2 INT NOT NULL,
    ...
    CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (KeyCol1 ASC, KeyCol2 ASC, KeyCol3 ASC)
}

此表目前有大约5200万行。如果我想检查一个特定行的存在,我可能会这样做:

SELECT 1 FROM MyTable WHERE KeyCol1 = 100 AND KeyCol2 = 200 AND KeyCol3 = 300

无论是否找到匹配的行,都会立即返回。如果我想检查是否存在多个不同的行,并返回找到哪些行,我将需要OR以及几个条件:

SELECT KeyCol1, KeyCol2, KeyCol3 FROM MyTable 
WHERE (KeyCol1 = 100 AND KeyCol2 = 200 AND KeyCol3 = 300)
   OR (KeyCol1 = 101 AND KeyCol2 = 201 AND KeyCol3 = 301)
   OR ...

即使我有超过300个不同的行,我也会立即返回。

问题:如果我采用完全相同的查询但将值拉出到参数中,则查询永远不会完成:

DECLARE @val1 INT = 100;
DECLARE @val2 INT = 200;
DECLARE @val3 INT = 300;
DECLARE @val4 INT = 101;
DECLARE @val5 INT = 201;
DECLARE @val6 INT = 301;
...
SELECT KeyCol1, KeyCol2, KeyCol3 FROM MyTable 
WHERE (KeyCol1 = @val1 AND KeyCol2 = @val2 AND KeyCol3 = @val3)
   OR (KeyCol1 = @val4 AND KeyCol2 = @val5 AND KeyCol3 = @val6)
   OR ...

我开始将参数数量一分为二,直到我发现192似乎是一个神奇的数字。使用上面最多192个参数的查询工作正常,它返回的速度几乎与内联硬编码值一样快(几毫秒的性能损失很小)。但是,只要我向查询添加第193个参数,它就会窒息。

我的问题:这是已知的,被接受的行为还是某种错误?如果它被接受了,那么我有什么选择可以尝试解决它?内联参数值有效,虽然它对我来说是次优解决方案(我必须破解实体框架以强制它不使用参数化查询)。

编辑 - 部分答案:正如@JoeW建议的那样,我将查询的执行计划与192个参数和193个参数进行了比较,它们确实不同。对于192个参数,the execution plan基本上是64 INDEX SEEK s(每行一个)MERGE JOIN。在193个参数中,the execution plan切换为单个INDEX SCAN,然后FILTER结果。很有意思。使用内联的所有值运行相同的查询会生成an execution plan,只会INDEX SEEK,不会JOINSCAN

因此,问题与参数的数量并不严格相关,而是与索引搜索的数量有关,但这只是参数化查询的问题。非常有趣。

2 个答案:

答案 0 :(得分:1)

尝试为3列为val1, val2, val3的所有变量创建临时表,并加入这两个表,您将获得答案。

CREATE TABLE TempTable {
    ColumnId INT NOT NULL IDENTITY(1,1),
    Col1 INT NOT NULL,
    Col2 INT NOT NULL,
    Col3 INT NOT NULL,
    CONSTRAINT PK_TempTable PRIMARY KEY CLUSTERED (ColumnId)
}

将所有变量数据插入表格。

INSERT INTO TempTable (Col1, Col2, Col3) 
VALUES (@val1, @val2, @val3), (@val4, @val5, @val6), ...

运行此查询:

SELECT t1.KeyCol1, t1.KeyCol2, t1.KeyCol3 
FROM MyTable t1 
INNER JOIN TempTable t2 ON t1.KeyCol1 = t2.Col1 AND t1.KeyCol2 = t2.Col2 AND t1.KeyCol3 = t2.Col3

答案 1 :(得分:0)

你让它运行多久了?我遇到过查询计划过于复杂而无法生成的问题。让我查看是否在让它运行一段时间后得到相同的错误。解决方法是将查询分解为较小的批次

SELECT KeyCol1, KeyCol2, KeyCol3 FROM MyTable 
WHERE (KeyCol1 = @val1 AND KeyCol2 = @val2 AND KeyCol3 = @val3)

UNION ALL

SELECT KeyCol1, KeyCol2, KeyCol3 FROM MyTable 
WHERE (KeyCol1 = @val4 AND KeyCol2 = @val5 AND KeyCol3 = @val6)

UNION ALL ...