EF Core 8 现在使用
WHERE IN
和 OPENJSON
的组合在 where 语句中内联值,而不是之前的 WHERE IN(...)
。
此更改已在文档中注明,说明的原因如下:
这里的值内联是通过这样一种方式完成的: SQL注入攻击的可能性。描述了使用 JSON 的更改 以下都是关于性能的,与安全无关。
不幸的是,
OPENJSON
我们 2017 年 SQL Server 实例的性能很差。
下面的查询由 EF Core 8 生成,运行需要 1.8 秒,并导致近 400,000 次读取:
DECLARE @__scheduleTagIds_0 nvarchar(4000) = N'[5835,5970,6563,6564,6565,6645,6835,6850,7034,7127]';
SELECT [s].[ScheduleTagId]
,[s].[MustStartProdBy]
FROM [ScheduleTagMustStartBy] AS [s]
WHERE [s].[ScheduleTagId] IN (
SELECT [s0].[value]
FROM OPENJSON(@__scheduleTagIds_0) WITH ([value] int '$') AS [s0]
)
如果我重构查询以使用标准
WHERE IN(...)
,执行时间将降至 120ms 和 29,000 次读取:
SELECT [s].[ScheduleTagId]
,[s].[MustStartProdBy]
FROM [ScheduleTagMustStartBy] AS [s]
WHERE [s].[ScheduleTagId] IN (5835,5970,6563,6564,6565,6645,6835,6850,7034,7127)
我的应用程序中有数百个使用
.Where(x => [collection].Contains(x.Id))
的查询,我非常担心在选择查询中看到的性能下降。
问题
OPENJSON(...
的唯一方法是将数据库兼容性级别更改为 120(低于 SQL Server 2016)。这不是一个理想的解决方案。还有其他方法可以限制/阻止 OPENJSON
的使用吗?OPENJSON
性能的配置?从分析器数据中可以清楚地看出,SQL Server 在使用 OPENJSON
时无法正确使用索引。根据文档,防止使用的唯一方法 OPENJSON(...是将DB兼容性级别更改为120(更低 比 SQL Server 2016)。这不是一个理想的解决方案。有没有 还有其他方法来限制/阻止 OPENJSON 的使用吗?
您不必将数据库兼容级别更改为 120。您可以调用
UseCompatibilityLevel(120)
来告诉 EF 生成旧式 SQL,无论兼容级别实际设置为什么。
还有一个选项可以避免这种全局设置,而只是恒定化有问题的特定查询。但我认为这还没有正式发布,所以你需要使用每日构建。
SQL Server 上是否有一些配置方面的东西可以 提高 OPENJSON 的性能?从分析器看来很清楚 SQL Server 在使用时无法正确使用索引的数据 开放 JSON。
它当然可以使用索引
OPENJSON
它只是可能选择不这样做。
当你传递常量时它可以确定
对于
OPENJSON
,它无法说出任何内容,因此它只能退回到猜测。这可能会导致不同的(更糟糕的)计划。