SQL Server 重建索引与重组索引区别

文章探讨了SQLServer中重建索引和重组索引的区别,包括它们对空间的需求、执行速度、事务日志生成以及锁请求。重建索引需要更多空间,适用于高碎片情况,而重组索引更节省空间,适合轻微碎片。事务日志方面,重建索引在FULL恢复模式下记录完整,重组索引则产生较小的日志。锁请求上,重建索引可能导致表锁定,重组索引则持有一种意向排他锁。文章建议根据碎片程度选择合适的索引维护策略。

在讨论索引碎片时,很多同学并不知道重建索引(ALTER INDEX ... REBUILD)和重组索引( ALTER INDEX ... REORGANIZE)之间的区别,所以下面就是这篇文章的主题。以下所说的仅适用于基于行的索引(不是列存储索引),同样适用于聚集索引或非聚集索引。

空间需求

重建索引是要在删除旧索引之后创建新索引,不管旧索引中存在多少的碎片。这意味着你需要有足够的可用空间来容纳新索引。

组索引首先将索引行挤压在一起以尝试释放一些索引页,然后将其页面重新调整,使其物理(分配)顺序与逻辑(键)顺序相同。这只需要一个 8KB 的页面作为移动页面的临时存储。因此,索引重组非常节省空间。

如果磁盘空间有限,对于分区表又无法利用单分区重建索引,则重组索引是比较好的方法。

算法速度

重建索引将始终构建一个新索引,即使没有碎片的索引(看你是否设置索引填充度)。重建所需的时间长度与索引的大小有关,而不是其中的碎片量。

重组索引只处理存在的碎片,碎片越多,重组所需的时间就越长。

这意味着对于碎片较少的索引(例如小于 30% 的碎片),重组索引通常会更快。但对于碎片较多的索引,通常重建索引会更快。所以我们通常设置, 0-5% 的碎片什么都不做,5%-30% 的碎片则重组索引,30%+ 重建索引。

生成的事务日志

在 FULL 恢复模式下,重建索引是完全记录的,因此事务日志需要在单个事务中容纳索引完整大小。这也意味着重建索引生成的事务日志可能需要进行镜像、发送到 AG 副本、复制扫描、备份等。

在 SIMPLE 和 BULK_LOGGED 恢复模式下,由离线重建索引生成的事务日志量将是最小的(在线索引重建总是完全记录)——只是按页面和区进行分配。但是,下一次执行日志备份(BULK_LOGGED 模式或切换到 FULL 模式)时也将包含重建更改的所有范围,因此日志备份的大小与在 FULL 恢复模式下重建索引完成的大小是一样的。这样做的好处是,在单个事务重建索引期间,不用考虑事务日志有较大的增长。

而在所有的恢复模式中,重组索引都是完全记录的,但只作为一系列小事务执行,因此不会导致事务日志异常增长。当然,事务日志仅为执行期间生成的大小,所以重组索引可能会少一些,因为它只处理存在的碎片。

锁请求

任何离线重建索引都持有表的架构修改锁(SCH-M)——不能更新或读取整个表。

任何在线重建索引都会在操作开始时获取一个短期共享表锁,在整个操作过程中持有一个意向共享锁(只会阻塞排他锁和架构修改锁),然后在操作结束时获得一个短期架构修改锁。从 SQL Server 2014 开始,你可以使用 WAIT_AT_LOW_PRIORITY 选项来延迟潜在的阻塞。

重组索引在整个操作过程中持有一个意向排他锁,它只会阻塞共享、排他和架构修改锁。

是否可中断

重建索引操作不能被中断,它是原子性的,要么全有要么全无,除非你想撤销并回滚该操作。但是在 SQL Server 2017 中,提供了一个可恢复的在线索引重建功能。

重组索引可以进行中断,前期处理的不会进行回滚,最糟糕的情况只是对当前正在进行的单页移动回滚。

是否报告进度

重建索引没有正确的进度报告。你可以通过Profiler 事件 Progress Report: Online Index Operation 中的 bigintdata1 列来对在线索引操作进行跟踪,这显示了旧索引的多少行已被扫描。你还可以通过查看 SPID 在sys.dm_exec_requests 中完成的页面读取次数推断。

重组索引操作参考 sys.dm_exec_requests 的 percent_complete 列,你可以轻松地衡量其剩余的工作量。事实上,DBCC INDEXDEFRAG 也用于进行进度报告,但不太优雅,它每 30 秒向你的连接打印一条进度消息。

统计信息

重建索引将始终使用等效于完全扫描(或采样,对于索引分区或索引已分区)重建索引列统计信息。

重组索引看不到索引的整体视图,因此无法更新统计信息,这意味着需要手动维护索引统计信息。

总结

正如你所看到的,在重建和重组之间有相当多的主要区别,但是对于你应该使用哪一个并没有正确的答案——那是你的选择。

如果你的索引维护例程总是重新构建而从不考虑重组,那么你应该重新考虑。为了节省时间和资源,通常更好的做法是重新组织轻微碎片化的索引,并重新构建严重碎片化的索引。

和往常一样,我推荐Ola Hallengren的免费代码,而不是编写你自己的索引维护解决方案(是的,其他人也做过类似的工作,但我认为Ola的代码是迄今为止最好的、使用最广泛的)。

 

SQL Server 中,重建索引是优化数据库性能的重要手段之一。重建索引可以减少索引碎片,提高查询效率,并改善整体数据库性能。以下是几种常见的重建索引方法及最佳实践。 ### 重建索引的方法 #### 1. 使用 `DBCC DBREINDEX` `DBCC DBREINDEX` 是一个用于重建指定表上的所有索引的命令。它可以重建单个表的索引,也可以通过游标遍历所有表来重建整个数据库索引。以下是一个重建整个数据库索引的示例: ```sql USE his; GO DECLARE @table_name VARCHAR(200); -- 查询数据库里的所有表名 DECLARE cursor_reindex CURSOR FAST_FORWARD READ_ONLY FOR SELECT name FROM sys.tables; -- 使用游标遍历表列表 OPEN cursor_reindex; FETCH NEXT FROM cursor_reindex INTO @table_name; WHILE @@FETCH_STATUS = 0 BEGIN -- 开始重建索引 DBCC DBREINDEX(@table_name); FETCH NEXT FROM cursor_reindex INTO @table_name; END; CLOSE cursor_reindex; DEALLOCATE cursor_reindex; ``` #### 2. 使用 `ALTER INDEX REBUILD` `ALTER INDEX REBUILD` 是一种更现代的方法,用于重建指定的索引。它提供了更多的选项,例如指定填充因子、排序顺序等。以下是一个重建单个索引的示例: ```sql USE databasename; GO ALTER INDEX ALL ON TableName REBUILD; ``` 如果需要重建整个数据库的所有索引,可以通过动态生成 SQL 语句来实现: ```sql USE databasename; GO DECLARE @name NVARCHAR(100); DECLARE authors_cursor CURSOR FOR SELECT [name] FROM sysobjects WHERE xtype = 'u' ORDER BY id; OPEN authors_cursor; FETCH NEXT FROM authors_cursor INTO @name; WHILE @@FETCH_STATUS = 0 BEGIN EXEC('ALTER INDEX ALL ON ' + @name + ' REBUILD'); FETCH NEXT FROM authors_cursor INTO @name; END; CLOSE authors_cursor; DEALLOCATE authors_cursor; ``` #### 3. 使用 `ALTER INDEX REORGANIZE` `ALTER INDEX REORGANIZE` 用于重组指定的索引,而不是完全重建。它适用于碎片化程度较低的索引,资源消耗较少。以下是一个重组索引的示例: ```sql USE databasename; GO ALTER INDEX IX_Employee_Name ON Employee REORGANIZE; ``` ### 最佳实践 - **监控索引碎片**:在决定是否重建重组索引之前,应定期监控索引的碎片化程度。可以通过查询 `sys.dm_db_index_physical_stats` 视图来获取索引的碎片化信息。 - **选择合适的重建方法**:对于碎片化程度较高的索引(通常超过 30%),建议使用 `ALTER INDEX REBUILD`;对于碎片化程度较低的索引(通常在 5% 到 30% 之间),可以使用 `ALTER INDEX REORGANIZE`。 - **避免在高峰时段执行重建操作**:重建索引是一个资源密集型操作,可能会影响数据库性能。因此,建议在低峰时段执行此类操作。 - **考虑填充因子**:重建索引时可以指定填充因子,以预留一定的空间,减少未来的页分裂。例如,使用 `DBCC DBREINDEX(@table_name, '', 90)` 可以设置填充因子为 90%。 - **定期维护计划**:建立定期的维护计划,自动执行索引重建重组操作,以保持数据库的高性能。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值