配置和维护具有许多插入和删除的表的最佳方法,平均而言是空的?

Tri*_*nko 5 performance sql-server delete index-maintenance bulk-insert performance-tuning

存在一个“批量查询”表,它有两列(BatchID、RecordID),它们都是 TSQL 类型的“uniqueidentifier”。唯一的聚簇键在(BatchID,RecordID)上,并且没有二级索引。

我们使用 SqlBulkCopy 将数千或数百万个 id 快速插入到单个批处理 id 下的表中,以便各种查询可以加入它以使用与该批处理关联的记录 id 集执行过滤。这种方法比尝试多个查询快得多,所有查询都在查询字符串中发送 id 列表。查询完成后,该批记录 ID 将被删除。当没有查询运行时,该表平均为空,但可能有数百个活动批次,因为我们每秒处理数千个可能使用该表的 API 请求。

我的问题是,DBA 需要什么样的维护步骤(如果有)来维护这些表。例如,它是否会从定期索引重建中受益,或者 SQL Server 是否会自行处理已删除行的清理(释放页块等)。此外,表或聚集索引是否有任何特殊配置会有所帮助,特别是考虑到标识符是随机 Guids(唯一标识符)。

一般我们使用最新版本的SQL Server,企业版。有些服务器在 Azure 中,有些在 AWS 中。

我也有兴趣听取替代方案。例如,我认为这种方法最适合永久表,但我也可以创建一个会话本地临时表作为事务的一部分,该表在完成时被删除,而不是从永久表中插入和删除行。我只是不知道相比之下会如何表现。

小智 6

根据我在 SQL Server 2016 Enterprise Edition 中使用永久表作为消息队列的类似过程的经验 - 因此它具有非常高的插入和删除率 - 我们发现每 5 到 10 分钟重建索引有利于强制删除记录清理。这极大地提高了表的读取性能。

在我们的例子中,数据库隔离级别是读提交快照,出队/删除过程删除记录的速度比幽灵清理过程清除记录的速度快。对于高幻影记录计数,选择​​一条记录有时需要 1-3 秒而不是 5-10 毫秒,因为 SQL 必须读取所有幻影记录,这由高扫描计数(带有set statistics io on)指示。

要检查幽灵记录的数量:

SELECT version_ghost_record_count, * 
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('[transport].[BatchTable]'), NULL, NULL, 'SAMPLED')
Run Code Online (Sandbox Code Playgroud)

https://docs.microsoft.com/en-us/sql/relational-databases/ghost-record-cleanup-process-guide?view=sql-server-2017#ghost-record-cleanup-task

鬼清除过程会按一定时间间隔自动运行(SQL Server 2012+ 每 5 秒一次,SQL Server 2008/2008R2 每 10 秒一次)并检查是否有任何页面被标记为鬼记录。如果它找到任何,那么它会删除标记为删除或重影的记录,每次执行最多触及10 页

在具有许多删除的高负载系统上,ghost 清理过程可能会导致性能问题,因为将页面保留在缓冲池中并生成 IO

我认为“最多 10 页”部分是我们的限制因素,因为高删除率超过了每次运行清理过程可以触及的页面数量。