Ola Hallengren索引维护 - 命令之间的时间间隔长吗?

我在所有服务器上运行Ola Hallengren脚本来进行索引和统计维护。当我查看命令日志表时,我注意到一个命令结束和下一个命令开始之间有很长的时间间隔。有时这个间隔超过一个小时。 其他人的系统是否也有这种情况?我能做些什么来缩短(我猜测的)发现项目之间的时间?以下是我使用的参数设置。
sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE [dbo].[IndexOptimize] 
@Databases = 'USER_DATABASES', 
@LogToTable = 'Y',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 50,
@FragmentationLevel2 = 80,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y' " -b
所以当我运行这个时:
SELECT DATEDIFF(MINUTE, cl.StartTime, cl.EndTime)
, *
FROM master.dbo.CommandLog AS cl
WHERE cl.StartTime > '2014-12-13'
ORDER BY cl.ID

我看到这个:

Sample output

3个回答

深入了解后,使用常见的查询来检索索引碎片化,即使在一个1.5TB的数据库上,返回160行的结果也需要大约一个小时的时间。
SELECT  s.name AS schemaname ,
        t.name AS tablename ,
        t.object_id ,
        i.name AS indexname ,
        i.index_id ,
        x.page_count ,
        x.avg_fragmentation_in_percent ,
        x.avg_page_space_used_in_percent ,
        i.type_desc
FROM    sys.dm_db_index_physical_stats(DB_ID(
                                ), NULL, NULL, NULL, 'LIMITED') x
        INNER JOIN sys.tables t ON x.object_id = t.object_id
        INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
        INNER JOIN sys.indexes i ON x.object_id = i.object_id
                                AND x.index_id = i.index_id
WHERE   x.index_id > 0
        AND alloc_unit_type_desc = 'IN_ROW_DATA'
        AND x.page_count > 1000;
这让我相信,当索引维护例程的这部分运行时,它在新数据库的开始阶段收集初始信息和构建命令时花费了很长时间。
SET @CurrentCommand12 = @CurrentCommand12 + 
'SELECT @ParamFragmentationLevel = MAX(avg_fragmentation_in_percent), 
@ParamPageCount = SUM(page_count) 
FROM sys.dm_db_index_physical_stats(
@ParamDatabaseID, @ParamObjectID, @ParamIndexID,     @ParamPartitionNumber, ''LIMITED'')     
WHERE alloc_unit_type_desc = ''IN_ROW_DATA'' AND     index_level = 0'

EXECUTE sp_executesql @statement = @CurrentCommand12, @params = N'@ParamDatabaseID int, 
@ParamObjectID int, @ParamIndexID int, @ParamPartitionNumber int, 
@ParamFragmentationLevel float OUTPUT, @ParamPageCount bigint OUTPUT', 
@ParamDatabaseID= @CurrentDatabaseID, @ParamObjectID = @CurrentObjectID, @ParamIndexID = 
@CurrentIndexID, @ParamPartitionNumber = @CurrentPartitionNumber, 
@ParamFragmentationLevel = @CurrentFragmentationLevel OUTPUT, @ParamPageCount = 
@CurrentPageCount OUTPUT

根本原因是DMF sys.dm_db_index_physical_stats扫描模式的结合。 (我在原始描述中对有限部分进行了强调) 函数执行的模式决定了用于函数的统计数据获取所执行的扫描级别。模式可以指定为LIMITED、SAMPLED或DETAILED。该函数遍历构成表或索引的指定分区的分配单元的页面链。无论运行在哪种模式下,sys.dm_db_index_physical_stats只需要一个意向共享(IS)表锁。 LIMITED模式是最快的模式,扫描的页面数量最少。对于索引,只扫描B树的父级页面(即叶级页面上方的页面)。对于堆,会检查关联的PFS和IAM页面,并以LIMITED模式扫描堆的数据页面。 在LIMITED模式下,compressed_page_count为NULL,因为数据库引擎只扫描B树的非叶级页面以及堆的IAM和PFS页面。使用SAMPLED模式可以获得compressed_page_count的估计值,使用DETAILED模式可以获得compressed_page_count的实际值。SAMPLED模式返回基于索引或堆中所有页面的1%样本的统计信息。SAMPLED模式的结果应视为近似值。如果索引或堆的页面数少于10,000页,则使用DETAILED模式。 DETAILED模式扫描所有页面并返回所有统计信息。 从LIMITED到DETAILED,模式逐渐变慢,因为每个模式执行的工作越多。要快速评估表或索引的大小或碎片化水平,请使用LIMITED模式。它是最快的,并且不会为索引的IN_ROW_DATA分配单元中的每个非叶级别返回一行数据。 参考:sys.dm_db_index_physical_stats (Transact-SQL) | Scanning Modes(Microsoft Docs) 即使Ola的脚本以“LIMITED”模式执行sys.dm_db_index_physical_stats,根据数据量的大小,扫描非常大的堆可能需要很长时间。而且,由于您正在使用@UpdateStatistics = 'ALL',这意味着告诉脚本更新所有统计信息(包括索引和列) ,其中也包括堆列的统计信息。 可能的解决方案 您可以考虑不更新所有对象的统计信息,而是将范围限制在索引上,或者考虑更改以下参数:
@OnlyModifiedStatistics = 'Y'

默认值为N

仅在最近的统计更新后有任何行被修改时才更新统计信息。

参考:SQL Server索引和统计信息维护 (ola.hallengren.com)


我曾见过这种行为 - 即使在线重建,你仍然需要一个模式修改(SCH-M)锁来更改索引。

在一个繁忙的表上,这可能需要一些时间来获取。


在意识到提问者是谁之后——我猜你已经考虑过了 :) - Lukek