Rom*_*anG 5 index sql-server execution-plan plan-cache
我们的应用程序使用 SQL Server 2014,我们遇到了与计划缓存相关的问题。
我们有一个参数化查询,它的执行计划取决于参数值。服务器缓存在某些情况下不是最佳的执行计划,然后将其用于所有后续查询。
细节:
我们有一个由以下列组成的表:
(
[Revision] [bigint] IDENTITY(1,1) NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
...A WHOLE LOT OF OTHER COLUMNS...
)
Run Code Online (Sandbox Code Playgroud)
这两列的含义很清楚,UserId是记录所属用户的Id,是记录Revision的自增索引。其他列并不重要,但它们存在并影响执行计划。
该表包含 ~40.000.000 行和 ~200.000 个不同UserId值,因此每个用户平均有 200 条记录。行永远不会更新,我们只使用 INSERT 和 DELETE 来修改数据。
我们的应用程序对此表执行以下查询:
SELECT * FROM SampleTable WHERE Revision > {someRevision} AND UserId = {someId}
Run Code Online (Sandbox Code Playgroud)
该表有两个索引:
Revision ascUserId asc, Revision asc当我手动执行此查询时,我看到执行计划取决于someRevision.
如果是比较接近的修订目前的最高值,则服务器使用Clustered Index Seek与Seek Predicate: Revision > someRevision
如果它没有关闭,服务器使用Index Seek (NonClustered)+Key Lookup (Clustered)和Seek Predicate: UserId = someId AND Revision > someRevision。
我们的应用程序使用 Linq-To-Sql 并生成参数化查询,它们如下所示:
exec sp_executesql N'SELECT * FROM [SampleTable] AS [t0]
WHERE ([t0].[Revision] > @p0) AND ([t0].[UserId] = @p1)',N'@p0 bigint,@p1
uniqueidentifier',@p0=1234,@p1='bc38dd12-238c-41a2-9dea-bb12ce105e6d'
Run Code Online (Sandbox Code Playgroud)
我使用dm_exec_cached_plans, dm_exec_sql_text,dm_exec_query_plan并了解到服务器将此查询的单个计划放入缓存中。因此,如果具有相应值的查询Revision首先出现,则使用的计划Clustered Index Seek将存储在计划缓存中,然后将用于所有后续查询。
它会导致过多的逻辑读取 (x10000) 和不可接受的查询执行时间,这些查询应该使用第二个计划 ( Index Seek (NonClustered)+ Key Lookup (Clustered)) 执行。
我还注意到服务器在计划之间切换的阈值(临界点)取决于统计数据,如果它过时,即使没有缓存,计划也可能不是最佳的,因为服务器错误地估计了Revision大于给一个。
此外,我们有大量具有相似用例的相似表,并且它们都有相同的问题。
我能做些什么来解决这个问题?
我可以尝试使用OPTION (RECOMPILE),这对于 Linq-To-Sql 来说并不容易,但它在性能方面看起来也不是非常理想。
我也可以更多地使用sp_create_plan_guide或破解 Linq-To-Sql 并尝试从WITH (INDEX(...))子句强制使用第二个计划,但正如我所说,有很多表具有相同的核心结构,所以这种方式看起来像很多手动工作.
一般来说,我的问题:
SQL Server 是否可以理解存储在缓存中的计划对于给定参数不是最佳的并且不使用它?
如果最佳执行计划取决于参数,是否有一些处理参数化查询的最佳实践?
这称为参数嗅探,它在 Erland Sommarskog 的史诗般的帖子中进行了广泛的介绍,应用程序中的速度慢,SSMS 中的速度快。
我什至不能在这里开始公正地对待它,但示例解决方案包括:
继续阅读Erland 的优秀文章——它不仅会在今天带来回报,而且随着您一次又一次地解决这个问题,它将继续为您的职业生涯带来回报。今天适用于您的查询的解决方案可能与您明天用于另一个查询的解决方案大不相同。
| 归档时间: |
|
| 查看次数: |
1759 次 |
| 最近记录: |