我已经研究一个存储过程性能问题一个多星期了,该问题与我在 Stackoverflow 上的其他帖子 here 相关。 。让我给你一些背景信息。
我们有一个每晚运行的进程,并由一个存储过程启动,该存储过程调用许多其他存储过程。许多被调用的存储过程调用其他存储过程,等等。我查看了一些被调用的过程,其中有各种令人恐惧的复杂内容,例如 XML 字符串处理、不必要的游标过度使用、过度使用 NOLOCK 提示,很少使用基于集合的处理等 - 这样的例子不胜枚举,非常可怕。
我们生产环境中的这个每晚流程平均需要 1 分 15 秒才能运行。有时需要2个小时才能运行,这是 Not Acceptable 。我在与生产相同的硬件上创建了一个测试环境并运行该过程。我第一次运行花了45分钟。如果我将数据库恢复到完全相同的点并再次运行它,则需要更长的时间:事实上,如果我多次重复此操作(恢复并重新运行),该过程将花费越来越长的时间,直到在 2 小时左右达到稳定状态。这真的让我很困惑,因为我每次都将数据库恢复到完全相同的点。服务器上没有其他用户数据库。
我想到了两条线索:
- 查询计划和参数欺骗
- 临时数据库
作为测试,我重新启动 SQL Server 以清除缓存和 tempdb,并使用相同的数据库恢复重新运行过程。该过程耗时 45 分钟。我重复了几次以确保它是可重复的 - 同样每次都需要 45 分钟。然后,我开始进行多项测试,尝试隔离 SQL Server 未重新启动时令人费解的运行时间增加:
使用 RECOMPILE 运行初始存储过程
在运行过程之前,执行DBCC FREEPROCCACHE以清除过程缓存
在运行该过程之前,先执行 CHECKPOINT,然后执行 DBCC DROPCLEANBUFFERS,以确保缓存为空且干净
执行以下脚本以确保所有存储过程都被标记为重新编译:
DECLARE @proc_schema SYSNAME DECLARE @proc_name SYSNAME DECLARE prcCsr CURSOR local FOR SELECT specific_schema, specific_name FROM INFORMATION_SCHEMA.routines WHERE routine_type = 'PROCEDURE' OPEN prcCsr FETCH NEXT FROM prcCsr INTO @proc_schema, @proc_name DECLARE @stmt NVARCHAR(MAX) WHILE @@FETCH_STATUS = 0 BEGIN SET @stmt = N'exec sp_recompile ''[' + @proc_schema + '].[' + @proc_name + ']''' -- PRINT @stmt -- DEBUG EXEC ( @stmt ) FETCH NEXT FROM prcCsr INTO @proc_schema, @proc_name END
在所有上述测试中,使用相同的数据库还原运行该过程所需的时间越来越长。我现在真的不知道该尝试什么。此时查看代码是一种选择,但实际上需要 3-6 个月才能进行优化,因为那里还有很大的改进空间。我真正感兴趣的是,为什么每次执行数据库恢复时,即使过程和缓冲区缓存已被清理,过程执行时间也会变长?
我也调查了 tempdb,并尝试清除其中的旧表,如我的其他 stackoverflow 帖子中所述,但我无法手动清除从表变量手动创建的临时表,而且它们似乎没有想要自行消失(即使在离开它们 24 小时后)。
任何有关进一步测试的见解或建议将不胜感激。我在 Windows 2003 R2 Ent 上运行 SQL Server 2005 SP3 64 位企业版。版本集群。
问候, 马克。
最佳答案
可能导致此问题的一件事是进程是否泄漏 XML 文档。这将导致 SQL Server 使用更多内存,并且部分内存可能会写入磁盘上的页面文件,从而导致进程变慢。
创建 XML 文档的代码如下所示:
EXEC sp_xml_preparedocument @idoc OUTPUT, @strXML
如果没有对应就会泄漏:
EXEC sp_xml_removedocument @idoc
XML 文档是存储在配置的 SQL Server 内存之外的 COM 对象。即使您将 SQL Server 设置为最多使用 5 GB,泄漏的 XML 文档也会使内存使用量超出此范围。
关于sql-server - 有趣的 SQL Server 性能调优问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1612414/