永不结束查询存储搜索


10

我从一开始说,我的问题/问题类似于之前的一个,但因为我不知道的原因或起始信息是一样的,我决定后,我的问题有一些更多的细节。

当前问题:

  • 在一个奇怪的时刻(工作日临近结束),生产实例开始出现异常行为:
    • 实例的CPU较高(从约30%的基准开始,它增加了约一倍,并且仍在增长)
    • 每秒增加的事务数(尽管应用程序负载未发生任何变化)
    • 空闲会话数增加
    • 从未显示此行为的会话之间发生奇怪的阻止事件(即使读取未提交的会话也导致了阻止)
    • 等待间隔的最长时间是第一页上的非页面锁,第二名是锁

初步调查:

  • 使用sp_whoIsActive,我们看到了由监视工具执行的查询决定运行速度非常慢,并占用大量CPU,这在以前是没有发生的。
  • 隔离级别未提交;
  • 我们查看了看到古怪数字的计划:StatementEstRows =“ 3.86846e + 010”,其中约150 TB的估计数据已返回
  • 我们怀疑原因是监视工具的查询监视功能引起了,因此我们禁用了该功能(我们还与提供程序一起打开了一张票证,以检查他们是否知道任何问题)
  • 从第一个事件开始,它又发生了几次,每次我们终止会话时,一切都恢复正常;
  • 我们意识到查询极为相似的一个查询在BOL使用MS用于查询存储监测-查询,最近在性能倒退(在时间上比较不同点)
  • 我们手动运行相同的查询并看到相同的行为(使用的CPU不断增加,闩锁等待时间增加,意外锁定等。)

有罪查询:

Select qt.query_sql_text, 
    q.query_id, 
    qt.query_text_id, 
    rs1.runtime_stats_id AS runtime_stats_id_1,
    interval_1 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi1.start_time), 
    p1.plan_id AS plan_1, 
    rs1.avg_duration AS avg_duration_1, 
    rs2.avg_duration AS avg_duration_2,
    p2.plan_id AS plan_2, 
    interval_2 = DateAdd(minute, -(DateDiff(minute, getdate(), getutcdate())), rsi2.start_time), 
    rs2.runtime_stats_id AS runtime_stats_id_2
From sys.query_store_query_text AS qt 
Inner Join sys.query_store_query AS q 
    ON qt.query_text_id = q.query_text_id 
Inner Join sys.query_store_plan AS p1 
    ON q.query_id = p1.query_id 
Inner Join sys.query_store_runtime_stats AS rs1 
    ON p1.plan_id = rs1.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi1 
    ON rsi1.runtime_stats_interval_id = rs1.runtime_stats_interval_id 
 Inner Join sys.query_store_plan AS p2 
    ON q.query_id = p2.query_id 
Inner Join sys.query_store_runtime_stats AS rs2 
    ON p2.plan_id = rs2.plan_id 
Inner Join sys.query_store_runtime_stats_interval AS rsi2 
    ON rsi2.runtime_stats_interval_id = rs2.runtime_stats_interval_id
Where rsi1.start_time > DATEADD(hour, -48, GETUTCDATE()) 
    AND rsi2.start_time > rsi1.start_time 
    AND p1.plan_id <> p2.plan_id
    AND rs2.avg_duration > rs1.avg_duration * 2
Order By q.query_id, rsi1.start_time, rsi2.start_time

设置和信息:

  • Windows Server 2012R2群集上的SQL Server 2016 SP1 CU4企业
  • 查询存储已启用并配置为默认值(未更改设置)
  • 从SQL 2005实例导入的数据库(仍处于兼容级别100)

实证观察:

  • 由于统计数据极其古怪,我们将所有在错误的估算计划中使用的* plan_persist **对象(尚无实际计划,导致查询从未完成)并检查了统计信息,该计划中使用的某些索引没有任何统计信息(DBCC SHOWSTATISTICS没有返回任何内容,请从sys.stats中选择,对某些索引显示NULL stats_date()函数

快速而肮脏的解决方案:

  • 在与查询存储或
  • 强制使用新的CE(跟踪标记)运行查询-这还将创建/更新必要的统计信息,或者
  • 将数据库的兼容性级别更改为130(因此默认情况下将使用新的CE)

因此,我的真正问题是:

为什么查询存储上的查询会导致整个实例的性能问题?我们是否在Query Store的bug领域?

PS:我将很快上传一些文件(打印屏幕,IO状态和计划)。

Dropbox上添加的文件。

计划1-生产中最初的古怪估计计划

计划2-测试环境中的实际计划,旧的CE(相同的行为,相同的统计数据)

计划3-测试环境中的实际计划,新的CE


1
我们最终禁用了查询存储,我们确定了根本原因是什么(我们肯定有多个问题)。在我的末端,CPU将增加我们单击以显示查询存储中统计信息的所有内容。
A_V '18年

Answers:


6

就像我在回答中所说的那样,经验测试表明sys.plan_persisted *系统对象上有索引,但没有在它们上面创建任何统计信息。我怀疑这是因为该数据库是从SQL 2005实例迁移而来的,并且在兼容级别100下保留了一段时间,因此没有使用新的CE。

行计数检查:

Select count(1) from NoNameDB.sys.plan_persist_runtime_stats with (nolock) --60362   
Select count(1) from NoNameDB.sys.plan_persist_plan with (nolock) --1853    
Select count(1) from NoNameDB.sys.plan_persist_runtime_stats_interval with (nolock) --671    
Select count(1) from NoNameDB.sys.plan_persist_query with (nolock) --1091    
Select count(1) from NoNameDB.sys.plan_persist_query_text with (nolock) --911

这表明最初的估计是错误的。使用DAC连接完成,否则无法查询这些表。

统计检查:

DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats_interval', plan_persist_runtime_stats_interval_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_runtime_stats', plan_persist_runtime_stats_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_cidx);    
DBCC SHOW_STATISTICS ('sys.plan_persist_plan', plan_persist_plan_idx1);    
DBCC SHOW_STATISTICS ('sys.plan_persist_query', plan_persist_query_cidx)    
DBCC SHOW_STATISTICS ('sys.plan_persist_query_text', plan_persist_query_text_cidx);

这表明某些索引的统计信息为空(缺失,无,零)。

初始修复:

UPDATE STATISTICS sys.plan_persist_runtime_stats WITH fullscan;
UPDATE STATISTICS sys.plan_persist_plan WITH fullscan;
UPDATE STATISTICS sys.plan_persist_runtime_stats_interval WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query WITH fullscan;
UPDATE STATISTICS sys.plan_persist_query_text WITH fullscan;

这种固定的统计信息使查询在10到12秒内完成。

第二个解决方法

(仅在测试环境中进行了验证),并且很可能是正确的查询(因为它显示了查询的最佳状态),是将数据库的兼容性级别更改为130。最终结果是,查询在大约10到12秒的时间内结束,正常数字统计信息(1万行)。

中间修正

DBCC TRACEON (2312) -- new CE

有关系统隐藏表统计信息的一些相关帮助


3

如果您在SSMS中打开实际计划并查看CPU使用率(或检查XML),就可以看到这个基本问题,它是TVF节点32。慢速查询存储查询中的罪魁祸首是内存TVF的重复访问

TVF成本

这些TVF返回多少行无关紧要,只需访问它们的次数即可。该解决方案将是您可以做的一切,以使您的计划远离多次阅读。

基于我有限的调试(包括技巧和花费的时间),我的假设是,每次执行TVF时都会扫描为查询存储数据的特定内存部分分配的全部内存。我无法使用sp_query_store_flush_db或来影响此内存分配DBCC FREESYSTEMCACHE

到目前为止,成功的解决方法包括计划指南,提示(OPTION(HASH JOIN, LOOP JOIN)到目前为止,对我来说已经足够好用)以及在AG的只读节点上运行查询存储查询。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.