出于好奇,我发现这个问题是因为 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 个参数,它就会阻塞。
我的问题:这是已知的,可接受的行为还是某种错误?如果这是可接受的行为,那么我必须尝试哪些选项来解决它?内联参数值是可行的,尽管它对我来说不是最佳解决方案(我必须破解 Entity Framework 以强制它不使用参数化查询)。
编辑——部分答案:正如@JoeW 建议的那样,我将查询的执行计划与 192 个参数和 193 个参数进行了比较,它们确实不同。对于 192 个参数,执行计划基本上是 64INDEX SEEK
秒(每行一个),它们MERGE JOIN
一起编辑。在 193 个参数处,执行计划切换到单个INDEX SCAN
然后FILTER
s 结果。很有意思。使用内联的所有值运行相同的查询会生成一个执行计划,该计划只执行INDEX SEEK
only、noJOIN
或SCAN
s。
所以问题不是严格与参数的数量有关,而是与索引搜索的数量有关,但这只是参数化查询的问题。确实非常有趣。