我们有一台 SQL Server 2019 CU18,我们发现 querystore 存在一个奇怪的问题。通常,每小时日志备份的平均大小为 40MB,但一旦我们启用 querystore,日志备份的平均大小就会变成 2.5GB。
根据 querystore,每小时执行 140,000 个查询。这大约相当于每秒执行 40 次。
这是我们的查询存储的配置:
ALTER DATABASE [db_name]
SET QUERY_STORE = ON
(
OPERATION_MODE = READ_WRITE
,CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 45)
,DATA_FLUSH_INTERVAL_SECONDS = 900
,MAX_STORAGE_SIZE_MB = 2048
,INTERVAL_LENGTH_MINUTES = 30
,SIZE_BASED_CLEANUP_MODE = AUTO
,QUERY_CAPTURE_MODE = AUTO
);
当我打开这么大的 logbackup 文件时,fn_dump_dblog
我发现同一秒内发生了多个事务。这些事务都名为“SwapPage”。
手术 | 语境 | 分配单元编号 | 页面 ID | 交易名称 |
---|---|---|---|---|
LOP_BEGIN_XACT | 空值 | 无效的 | 无效的 | 交换页面 |
LOP_INSYSXACT | LCX_INDEX_INTERIOR | 72057594047692800 | 0001:00056321 | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:000a871c | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:0000041b | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:0000041c | 无效的 |
页面格式化 | 链接重组页面 | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_修改头 | 链接重组页面 | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:000a871c | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:0000041c | 无效的 |
插入行 | LCX_CLUSTERED | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_修改_行 | LCX_INDEX_INTERIOR | 72057594047692800 | 0001:00056321 | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:0000041b | 无效的 |
LOP_修改头 | LCX_HEAP | 72057594047692800 | 0001:0000041b | 无效的 |
锁定迁移 | 空值 | 无效的 | 0001:000a8715 | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:000a8715 | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:0000041c | 无效的 |
LOP_INSYSXACT | 链接重组页面 | 72057594047692800 | 0001:0000041b | 无效的 |
LOP_INSYSXACT | LCX_CLUSTERED | 72057594047692800 | 0001:000a871c | 无效的 |
LOP_INSYSXACT | LCX_INDEX_INTERIOR | 72057594047692800 | 0001:00056321 | 无效的 |
提交XACT | 空值 | 无效的 | 无效的 | 无效的 |
分配单元指向plan_persist_runtime_stats。
在Paul White的评论之后,我设置了一个扩展事件来捕获query_store_index_rebuild_started
和query_store_index_rebuild_finished
。令我惊讶的是,Querystore 正在进行索引重建。以下是此跟踪的结果:
事件 | 时间戳 | 当前大小 |
---|---|---|
query_store_index_rebuild_started | 2024-12-05 07:51:10.353 | 874208 |
查询存储索引重建已完成 | 2024-12-05 07:52:29.073 | 868832 |
query_store_index_rebuild_started | 2024-12-05 08:20:58.497 | 873504 |
查询存储索引重建已完成 | 2024-12-05 08:22:18.320 | 869152 |
query_store_index_rebuild_started | 2024-12-05 08:36:03.147 | 874528 |
查询存储索引重建已完成 | 2024-12-05 08:37:19.670 | 869664 |
query_store_index_rebuild_started | 2024-12-05 09:06:00.943 | 874336 |
查询存储索引重建已完成 | 2024-12-05 09:07:12.750 | 870304 |
看起来索引重建在 874MB 左右开始,Querystore 的最大大小设置为 2048。
我还将事件的堆栈跟踪包含query_store_index_rebuild_started
在扩展事件中。
sqllang!XeSqlPkg::CollectClientHostnameActionInvoke sqllang!XeSqlPkg::CollectDatabaseIdActionInvoke sqllang!XeSqlPkg::CollectDatabaseNameActionInvoke sqllang!XeSqlPkg
::CollectNtUsernameActionInvoke sqllang!XeSqlPkg::CollectSessionIdActionInvoke sqllang!XeSqlPkg::CollectTSqlStack<XE_ActionForwarder> sqllang!XeSqlPkg::CollectTSqlStackActionInvoke qds!XeQdsPkg::query_store_index_rebuild_started::Publish
qds!CDBQDS::ReclaimFreePages
qds!CDBQDS::DoSizeRetention
qds!CDBQDS::ProcessQdsBackgroundTask
qds!CQDSManager::AcquireGenericQdsDbAndProcess<<lambda_e51628d7833f66b5a045fa5bf2d27953>>
qds!CDBQDS::ProcessQdsBackgroundTask
sqldk!SOS_Task::Param::Execute
sqldk!SOS_Scheduler::RunTask
sqldk!SOS_Scheduler::ProcessTasks
sqldk!SchedulerManager::WorkerEntryPoint
sqldk!SystemThreadDispatcher::ProcessWorker
sqldk!SchedulerManager::ThreadEntryPoint
KERNEL32+0x17AC4
ntdll+0x5A8C1
我曾希望找到触发索引重建的原因,但没有那么幸运。
在Zikato的一些指导下,我在跟踪中添加了一些额外的查询存储相关事件。这表明,只有query_store_size_retention_cleanup_started
发生事件时才会触发索引重建。
重建:
每次运行清理时都会删除 0KB,但显然需要重建。让我感到困惑的是清理事件的出现。我以为只有当 querystore 达到最大存储大小的 90% 时才会触发此事件。
增加 querystore 的最大大小没有任何区别。
有人遇到过同样的问题吗?有人能解释一下发生了什么吗?实例上的其他数据库没有这个问题。