由于事务日志空间不足,SQL Server 2012上的“ ALTER INDEX ALL REBUILD”操作失败。索引从未进行过重组或重建,因此几乎所有索引上的碎片都超过80%。
数据库使用简单的恢复模型。我假设在命令的“ ALL”形式执行的每个索引操作之后,在下一次重建索引之前将刷新事务日志数据。这是它的实际工作方式,还是索引重建记录为好像是单个事务的一部分?
换句话说,是否可以通过编写脚本来分别执行每个重建来减少事务日志的增长?还有其他要考虑的因素吗?
由于事务日志空间不足,SQL Server 2012上的“ ALTER INDEX ALL REBUILD”操作失败。索引从未进行过重组或重建,因此几乎所有索引上的碎片都超过80%。
数据库使用简单的恢复模型。我假设在命令的“ ALL”形式执行的每个索引操作之后,在下一次重建索引之前将刷新事务日志数据。这是它的实际工作方式,还是索引重建记录为好像是单个事务的一部分?
换句话说,是否可以通过编写脚本来分别执行每个重建来减少事务日志的增长?还有其他要考虑的因素吗?
Answers:
我假设在命令的“ ALL”形式执行的每个索引操作之后,在下一次重建索引之前将刷新事务日志数据。这是它的实际工作方式,还是索引重建记录为好像是单个事务的一部分?
1)日志刷新:SIMPLE恢复模型不会在每次事务处理后而是在检查点清除日志。(更多信息的链接)
2a)全部重建:是的,全部重建作为单个事务工作。索引重建在其中具有自己的事务,但是整个操作要到最后才完全提交。因此,可以的,您可以通过重建单个索引(并可能发出CHECKPOINT命令)来限制日志文件的增长。
2b)证明!在这里,有一个演示脚本。(内置于2016 dev)首先,建立一个带有表和索引的测试数据库:
USE master
GO
CREATE DATABASE Test_RebuildLog
GO
ALTER DATABASE Test_RebuildLog
SET RECOVERY SIMPLE
GO
USE Test_RebuildLog
GO
CREATE TABLE IndexTest
(ID int identity(1,1),
a char(1),
b char(1))
CREATE CLUSTERED INDEX CIX_IndexTest_ID ON IndexTest(ID)
CREATE INDEX IX_IndexTest_a ON IndexTest(a)
CREATE INDEX IX_IndexTest_b ON IndexTest(b)
INSERT IndexTest
(a,b)
VALUES ('a','b'),('z','y'),('s','r')
现在,您可以比较REBUILD ALL和单独重建之间的日志活动
CHECKPOINT
GO
ALTER INDEX ALL ON IndexTest REBUILD
SELECT *
FROM sys.fn_dblog(NULL,NULL)
WHERE Operation = 'LOP_COMMIT_XACT'
OR Operation = 'LOP_BEGIN_XACT'
GO
CHECKPOINT
GO
ALTER INDEX CIX_IndexTest_ID ON IndexTest REBUILD
ALTER INDEX IX_IndexTest_a ON IndexTest REBUILD
ALTER INDEX IX_IndexTest_b ON IndexTest REBUILD
SELECT *
FROM sys.fn_dblog(NULL,NULL)
WHERE Operation = 'LOP_COMMIT_XACT'
OR Operation = 'LOP_BEGIN_XACT'
GO
请注意,直到重新构建全部结束后,才提交第一个未完成的事务(对我来说,事务ID为0000:000002fa),但是对于逐索引重建,它们是连续提交的。
就目前而言,这是单笔交易。
对于离线重建而言,这个问题并不重要。当然是单笔交易。想象一下,如果该操作将每个索引分成自己的事务,将会造成严重破坏,因为在提交时必须释放锁,然后重新获取它们,这将导致该锁。释放关键表SCH-M锁后,可能会删除索引并创建新索引,该语句将如何处理此类情况?更不用说该表可能会被删除,甚至在两个事务之间重新创建!包括删除表并使用相同的对象ID创建另一个表的情况(是的,它可能发生)...
如果您扩大问题以说如果索引重建是在线重建会怎样呢?它是单笔交易还是很多笔交易?答案很复杂,因为实际上涉及多个内部事务。但是,关键是存在一个跨整个操作的整体弓形事务(ALTER语句),并且这会将日志固定在适当的位置(无法截断),因此需要相应地计划操作以允许约1.6倍的数据FULL恢复模式的数据大小,或BULK_LOGGED / SIMPLE模式的数据大小的0.2倍。有关更多详细信息,请参见链接的纸张。
您可能会争辩说,为什么脱机构建不使用与在线模式相同的内部事务,并拆分操作?我提到的有关在单个索引操作之间更改/删除表的问题(即表“模式稳定性”)仍将需要有一个包含事务的事务,该事务在整个语句期间将SCH-S保留在表上。由于此事务在恢复期间还必须保留SCH-S,因此必须对其进行记录,因此将存在BEGIN XACT日志记录,该记录将固定日志并在语句的整个持续时间内防止被截断。我知道此特定问题已在SQL 2016-2017时限内解决(由于SQL Azure日志大小问题),但我不确定取得了什么进展。看起来现在正在预览中:可恢复的联机索引重建在SQL Server 2017 CTP 2.0的公共预览中。
Rdfozz是正确的,这是决定是否可以基于当前存储来重建最大索引的最佳方法。只要dm_exec_requests
在操作发生时运行(或SQL事件探查器),即可查看是否正在重建所有索引。我还将考虑将恢复模型更改为批量记录。这就是我的工作,并且在窗口期间仍然有事务日志备份。参见下面的文章
https://technet.microsoft.com/zh-cn/library/ms191484(v=sql.105).aspx