我们在 Windows 2022 VM(8 个 vCPU 核心)上安装了 SQL Server 2022 Enterprise(16.0.4131.2),其中一个数据库上的查询存储存在问题。
下面是我在一个特定数据库上重现该问题所采取的步骤顺序以及我对此所做的观察:
1 –服务器处于空闲状态,仅有少量用户生成负载,且 CPU 利用率可忽略不计。
2 –查询存储已关闭,并且有问题的数据库为空,如下面的查询所示。
3 -当我将查询存储切换到 READ_WRITE 模式时,大约 10 - 15 分钟内一切都很正常。然而,在这段时间之后,服务器的 CPU 利用率突然上升到 15-20% 请参阅下面的活动监视器屏幕截图。
等待统计数据显示SOS_SCHEDULLER_YELD和PREEMPTIVE_OS_QUERYREGISTRY等待量大幅增加- 它们成为该时间段内最热门的服务器等待类型。
产生的 CPU 利用率似乎是由内部后台进程 (SPID < 51) 产生的,该进程与有问题的用户数据库上的 Service Broker 活动有关。数据库本身并未启用 Service Broker 功能。
4 –高 CPU 利用率、上述等待和上述 SPID 活动将持续出现,直到数据库上的查询存储被关闭。
如果我保持查询存储处于打开状态,则没有任何潜在“自我恢复”的迹象。一旦关闭,CPU 利用率就会下降,等待就会消失,SPID 会停止生成负载并进入“休眠”状态。将查询存储切换到 READ_ONLY 模式没有帮助。必须关闭查询存储才能解决问题。
当问题触发时,查询存储中没有任何大量数据 - 见下文(QS 关闭后进行的查询)。
其他相关观察
如果我打开(READ_WRITE)查询存储并让它运行一段时间,但时间不足以触发问题,然后将其切换到 READ_ONLY,则不会在上述 10-15 分钟的时间段内触发问题。但是,如果我稍后将查询存储切换到 READ_WRITE,则几乎会立即触发该问题。
当问题触发时,用户负载增加,可以看到在标准条件下需要几毫秒才能处理的数据库使用查询开始变慢,并且还显示不可忽略的 PREEMPTIVE_OS_QUERYREGISTRY 等待(根据下面显示的 sp_WhoIsActive)。这些查询肯定不会对 Windows 注册表进行查询。
我们在几个其他 SQL Server 实例上拥有相同的数据库(即相同的结构),具有相同的负载模式(甚至更大的数据和查询量),并且查询存储在那里运行良好。似乎查询存储中只有这个特定的数据库出现了问题。
重要的是,该数据库的查询存储最初已满,并且触发了“基于大小的清理过程”,并且 SQL Server(可能)在此期间重新启动。我怀疑该数据库中的 QS 中存在与此相关的问题... 我也尝试了sys.sp_query_store_consistency_check过程,但没有成功。
一旦通过关闭 QS 触发并“暂停”该问题,那么当再次打开 QS(未事先进行清理)时,该问题似乎几乎立即再次被触发。
在这种情况下,查询存储对于数据库来说完全不可用。有什么办法可以解决这个问题吗?
更新日期 2024-08-01
根据 Paul White 评论的提示,我对 CE_FEEDBACK 数据库范围选项进行了一些实验,它似乎是真正的触发器。行为如下所述:
我以前尝试的未清除的查询存储(仅几百个捕获查询)作为起点。
- 当我设置 CE_FEEDBACK = OFF 并将 QS 转为 READ_WRITE 时,该问题不会触发。
- 当我设置 CE_FEEDBACK = ON 并将 QS 转为 READ_WRITE 时,问题几乎立即触发。
- 当我设置 CE_FEEDBACK = OFF 并将 QS 设置为 READ_WRITE 时,问题不会触发。然后(在运行 QS 的情况下)我将 CE_FEEDBACK = ON。问题再次立即触发。有趣的是,当我再次设置 CE_FEEDBACK = OFF 时,这不足以阻止该问题。必须关闭 QS 才能阻止它。
工作量类型
由于该问题似乎也与工作负载类型有关,我将尝试在这里描述它,因为模式非常简单。它几乎 99% 都是临时的,具有以下查询模式:
- 实验期间执行的查询中约有 85% 是与表变量的简单连接。传递给变量的行数从 +/- 10 到 +/- 500 不等。源数据库表在查询之间有所不同,但执行计划模式相同,如下所示。
- 其余工作负载是遵循以下模式的查询。这部分的问题在于,由于参数的高度可变性(参数数量经常变化),因此能够在几天内用“唯一”查询填充 2GB 查询存储,但当前情况并非如此
我可以想象,很可能工作量的第一部分对于 CE_FEEDBACK 来说就是有问题的部分。
问题在于基于该数据库的工作负载和查询的 CE 反馈机制,以及 CE 反馈 QDS 集成的设计方式。
查看跟踪,热堆栈确实是 QDS,但其中
RunCEFeedbackAnalysis
有 1000 个切割的死亡,GetStmt
似乎被执行以获取该数据库的 QDS 中的每个项目。我认为一个鲜为人知的事实是,UCS(在幕后利用服务代理)用于执行 QDS 项目的任务,这就是为什么您看到该线程看起来像服务代理线程,但实际上不是。您也可以在上面的跟踪中看到这一点
CSbTask::BeginTaskStart
。因为我们知道数据库范围的设置是什么,并且进行了更新,所以您已经确认关闭 CE 反馈确实可以阻止该问题,这也是堆栈所建议的。
目前,您可以关闭 CE Feedback,以避免在该数据库中遇到此问题,或者转到没有该功能的兼容级别。如果不深入研究数据库工作负载和 QDS,很难说这是否可以在 SQL 中更有效地完成,或者这是否是数据库工作负载/QDS 设置不太合适的极端情况,这肯定超出了本网站的范围。
如果您有协议,您可以向 Microsoft 开具支持票,尽管不会有任何立即的变化或结果,而且如果有的话,它会在遥远的未来发生变化。