index rebuild vs index coalesce vs index shrink

本文通过实验对比了REBUILD、COALESCE与SHRINK三种索引优化方式的区别,包括它们在空间使用、锁使用及效率方面的表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当索引中碎片比较严重时,我们可以通过REBUILD COALESCE  SHRINK来回收索引空间。下面我们通过实验来比较一下这三种方式具有哪些不同

SQL> create table t1(c1 number,c2 number,c3 number);

表已创建。

已用时间:  00: 00: 00.03
SQL> insert into t1  select rownum,rownum,rownum from dual connect by level < 1000000;

已创建 999999 行。

已用时间:  00: 00: 03.69
SQL> commit;

提交完成。

已用时间:  00: 00: 00.01
SQL> create index rebuild_ind on t1(c1);

索引已创建。

已用时间:  00: 00: 10.76
SQL> create index coalesce_ind on t1(c2);

索引已创建。

已用时间:  00: 00: 14.74
SQL> create index shrink_ind on t1(c3);

索引已创建。

已用时间:  00: 00: 11.09
SQL> analyze table t1 compute statistics for table for all indexes for all columns;

表已分析。

已用时间:  00: 00: 16.02
SQL> delete from t1 where mod(c1,10) <> 0;

已删除900000行。

已用时间:  00: 06: 04.51
SQL> commit;

提交完成。

已用时间:  00: 00: 00.01
SQL> analyze table t1 compute statistics for table for all indexes for all columns;

表已分析。

已用时间:  00: 00: 02.12

SQL> analyze index rebuild_ind validate structure;

索引已分析

已用时间:  00: 00: 00.15
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
REBUILD_IND				3	2304	 312317      212318	  2226	     2225
	 5    17839236	  5003533	  29
--删除后,bf_blks为2226,说明叶子节点没有释放,但是如果以后有插入操作,空的叶子节点是可以重用的,即部分空块即在索引的双向链条上没有释放,但同时还在空块的链条上从而可以重用

已用时间:  00: 00: 00.02
SQL> select segment_name,blocks from user_segments where segment_name like '%IND';

SEGMENT_NAME									      BLOCKS
--------------------------------------------------------------------------------- ----------
REBUILD_IND										2304
COALESCE_IND										2304
SHRINK_IND										2304

已用时间:  00: 00: 00.08
SQL> analyze index coalesce_ind validate structure;

索引已分析

已用时间:  00: 00: 00.14
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
COALESCE_IND				3	2304	 286859      186860	  2226	     2225
	 5    17839236	  4596205	  26


已用时间:  00: 00: 00.01
SQL> analyze index shrink_ind validate structure;

索引已分析

已用时间:  00: 00: 00.11
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
SHRINK_IND				3	2304	 244024      144025	  2226	     2225
	 5    17839236	  3910845	  22


已用时间:  00: 00: 00.00
SQL> alter index rebuild_ind rebuild;

索引已更改。

已用时间:  00: 00: 01.58

SQL> alter index coalesce_ind coalesce;

索引已更改。

已用时间:  00: 00: 07.03
SQL> alter index shrink_ind shrink space;

索引已更改。

已用时间:  00: 01: 01.65
SQL> analyze index rebuild_ind validate structure;

索引已分析

已用时间:  00: 00: 00.06
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
REBUILD_IND				2	 256	  99999 	  0	   222	      221
	 1     1783140	  1591506	  90
--重建索引,索引的空间重新分配

已用时间:  00: 00: 00.01
SQL> analyze index coalesce_ind validate structure;

索引已分析

已用时间:  00: 00: 00.05
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
COALESCE_IND				3	2304	  99999 	  0	   223	      222
	 5     1823248	  1591516	  88
--coalesce后,索引中的空块在双向链条上剔除,但是在空块链条上保留,因此索引占用的总空间并没有变化

已用时间:  00: 00: 00.01
SQL> analyze index shrink_ind validate structure;

索引已分析

已用时间:  00: 00: 00.06
SQL> select name,height,blocks,lf_rows,del_lf_rows,lf_blks,br_rows,br_blks,btree_space,used_space,pct_used from index_stats;

NAME				   HEIGHT     BLOCKS	LF_ROWS DEL_LF_ROWS    LF_BLKS	  BR_ROWS
------------------------------ ---------- ---------- ---------- ----------- ---------- ----------
   BR_BLKS BTREE_SPACE USED_SPACE   PCT_USED
---------- ----------- ---------- ----------
SHRINK_IND				3	 248	  99999 	  0	   223	      222
	 5     1823248	  1591516	  88
--shrink后,索引的空块在段空间上释放

已用时间:  00: 00: 00.00
SQL> select segment_name,blocks from user_segments where segment_name like '%IND';

SEGMENT_NAME									      BLOCKS
--------------------------------------------------------------------------------- ----------
REBUILD_IND										 256
COALESCE_IND										2304
SHRINK_IND										 248

已用时间:  00: 00: 00.05

在空间使用情况上:

coalesce会整合索引空间,将利用率不高的块整合为利用率高的块,会将整理出的空块在索引结构的双向链条上释放,但是仍然保留在段内的空闲空间内。

shrink会将空块释放出段空间

rebuil重建索引因此段空间也是重建的


下面我们再来看一下锁的使用情况:

session 1:操作后不提交

SQL> select distinct sid from v$mystat;

       SID
----------
       179

SQL> update t1 set c1=c1+2,c2=c2+1,c3=c3+1;

session 2:

SQL> alter index rebuild_ind rebuild;
alter index rebuild_ind rebuild
            *
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源, 或者超时失效


已用时间:  00: 00: 00.00

SQL> alter index coalesce_ind coalesce;

索引已更改。

已用时间:  00: 00: 19.65
SQL> alter index shrink_ind shrink;
alter index shrink_ind shrink
                            *
第 1 行出现错误:
ORA-10630: Illegal syntax specified with SHRINK clause


已用时间:  00: 00: 00.00
SQL> alter index shrink_ind shrink space;
shrink 操作被阻塞,查看锁的使用情况

SQL> l
  1* select sid,type,id1,id2,lmode,request,block  from v$lock where sid in (select sid from v$session where username='SCOTT')
SQL> /

       SID TY	     ID1	ID2	 LMODE	  REQUEST      BLOCK
---------- -- ---------- ---------- ---------- ---------- ----------
	19 TX	  524289       2423	     6		0	   0
	19 TO	    5124	  1	     3		0	   0
	19 AE	     100	  0	     4		0	   0
	19 TO	   68064	  1	     3		0	   0
	19 SK	       7   16784210	     6		0	   0
	19 TX	  786454       1823	     0		4	   0
	19 TM	   89669	  0	     2		0	   0
       179 AE	     100	  0	     4		0	   0
       179 TX	  786454       1823	     6		0	   1
       179 TM	   89669	  0	     3		0	   0

已选择10行。

提交session1,后

SQL> alter index shrink_ind shrink space;

索引已更改。

已用时间:  00: 02: 51.02

总结:rebuild和shrink 不是"LOCK FRIENDLY",COALESCE是”lock friendly“,shrink does take a lock during the space release time

另外:如果索引的碎片情况非常严重,则rebuil的效率是较高的,而如果只是小部分索引的空间利用率不高,则COALESCE的效率是比较好的










<think>我们正在讨论如何重建数据库索引。根据用户提供的引用和之前的问题,用户已经了解索引失效(UNUSABLE)的处理方法,现在想了解重建索引的具体方法。注意,用户的问题中提到了多个引用,包括Oracle和SQL Server的重建方法,但用户没有指定数据库类型。因此,我们需要综合回答,并区分不同数据库。 根据引用[1]和[2],重建索引是提高数据库性能的重要手段。引用[2]给出了一个具体的重建索引的SQL语句示例(针对主键索引)。引用[3]则介绍了SQL Server通过维护计划向导自动重建索引的方法。引用[4]提到了Oracle索引创建前的检查规范。 由于用户之前的问题是关于Oracle索引失效(UNUSABLE)的,因此我们重点回答Oracle,同时兼顾SQL Server,因为用户引用了两种数据库的内容。 重建索引的步骤: 1. 确定需要重建的索引:通过查询数据字典视图(如DBA_INDEXES, DBA_IND_PARTITIONS)来找到状态为UNUSABLE的索引(Oracle)或碎片化严重的索引(SQL Server)。 2. 选择重建方法:手动重建或自动重建(通过脚本或维护计划)。 3. 执行重建:使用ALTER INDEX ... REBUILDOracle)或ALTER INDEX ... REORGANIZE/REBUILD(SQL Server)。 4. 验证重建结果:再次检查索引状态或碎片情况。 下面分别针对Oracle和SQL Server进行说明: ### Oracle数据库重建索引方法 1. **手动重建单个索引**: ```sql ALTER INDEX [schema.]index_name REBUILD [ONLINE] [TABLESPACE tablespace_name] [PARALLEL n]; ``` 选项说明: - `ONLINE`:在线重建,重建过程中允许对基表进行DML操作。 - `TABLESPACE`:指定重建索引存放的表空间,如果不指定则使用原来的表空间。 - `PARALLEL`:并行度,可以加快重建速度。 2. **重建分区索引的特定分区**: ```sql ALTER INDEX [schema.]index_name REBUILD PARTITION partition_name; ``` 3. **批量重建所有失效索引**: 可以使用PL/SQL块来重建所有状态为UNUSABLE的索引: ```sql BEGIN FOR idx IN (SELECT owner, index_name FROM dba_indexes WHERE status = 'UNUSABLE') LOOP EXECUTE IMMEDIATE 'ALTER INDEX ' || idx.owner || '.' || idx.index_name || ' REBUILD ONLINE'; END LOOP; END; / ``` 4. **重建后的验证**: 重建后,再次查询`DBA_INDEXES`和`DBA_IND_PARTITIONS`视图,确保索引状态变为VALID。 ### SQL Server数据库重建索引方法 1. **手动重建单个索引**: ```sql -- 重建索引 ALTER INDEX index_name ON table_name REBUILD; -- 重新组织索引(碎片较少时使用) ALTER INDEX index_name ON table_name REORGANIZE; ``` 2. **重建表中所有索引**: ```sql ALTER INDEX ALL ON table_name REBUILD; ``` 3. **使用维护计划向导自动重建索引(引用[3])**: 在SQL Server Management Studio中: - 右键点击“管理”->“维护计划”->“维护计划向导”。 - 输入计划名称,设置计划周期。 - 选择“重新生成索引”任务,选择数据库,然后完成向导。 这样就会定期自动重建索引。 4. **使用脚本重建所有数据库的索引**: ```sql -- 生成重建所有索引的脚本 DECLARE @TableName VARCHAR(255) DECLARE @IndexName VARCHAR(255) DECLARE @SQL NVARCHAR(MAX) DECLARE TableCursor CURSOR FOR SELECT '[' + IST.TABLE_SCHEMA + '].[' + IST.TABLE_NAME + ']' AS TableName, '[' + SI.name + ']' AS IndexName FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS PS JOIN sys.indexes AS SI ON PS.object_id = SI.object_id AND PS.index_id = SI.index_id JOIN INFORMATION_SCHEMA.TABLES AS IST ON PS.object_id = OBJECT_ID(IST.TABLE_SCHEMA + '.' + IST.TABLE_NAME) WHERE PS.avg_fragmentation_in_percent > 30 -- 碎片率大于30%则重建 AND SI.index_id > 0 -- 排除堆 AND IST.TABLE_TYPE = 'BASE TABLE' OPEN TableCursor FETCH NEXT FROM TableCursor INTO @TableName, @IndexName WHILE @@FETCH_STATUS = 0 BEGIN SET @SQL = 'ALTER INDEX ' + @IndexName + ' ON ' + @TableName + ' REBUILD' PRINT @SQL -- EXEC sp_executesql @SQL -- 实际执行时去掉注释 FETCH NEXT FROM TableCursor INTO @TableName, @IndexName END CLOSE TableCursor DEALLOCATE TableCursor ``` 5. **验证重建结果**: 可以通过以下查询查看索引碎片情况: ```sql SELECT DB_NAME() AS DatabaseName, OBJECT_NAME(IPS.object_id) AS TableName, SI.name AS IndexName, IPS.avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS IPS JOIN sys.indexes AS SI ON IPS.object_id = SI.object_id AND IPS.index_id = SI.index_id WHERE IPS.avg_fragmentation_in_percent > 0 ``` ### 注意事项 1. **重建时机**:在业务低峰期进行,避免影响正常业务。 2. **资源消耗**:重建索引会消耗大量I/O和CPU资源,特别是大表索引。使用并行(Oracle)或分步执行(SQL Server)可以减轻影响。 3. **空间要求**:重建索引需要额外的临时空间,确保表空间(Oracle)或文件组(SQL Server)有足够空间。 4. **锁机制**:在Oracle中,使用`ONLINE`选项可以最小化锁的影响;在SQL Server中,重建索引(REBUILD)会锁表,而重新组织(REORGANIZE)是联机操作,但速度较慢。 5. **监控**:重建后,应监控数据库性能,确认索引重建的效果。 通过以上步骤,您可以有效地重建数据库索引,恢复数据库性能[^1][^2][^3][^4]。 ### 相关问题 1. 如何监控数据库索引的碎片情况? 2. 重建索引和重组索引有什么区别? 3. 在Oracle中,重建索引时有哪些可用的高级选项? 4. 在SQL Server中,如何设置自动维护索引的任务?</think>### 数据库索引重建方法 索引重建是解决索引失效、碎片化或性能下降的核心手段。以下是不同数据库的重建方法,结合最佳实践和注意事项: --- ### **一、通用重建方法(手动执行)** #### **1. 单索引重建** ```sql -- Oracle ALTER INDEX 索引所有者.索引名 REBUILD [ONLINE] [PARALLEL 4]; -- SQL Server ALTER INDEX 索引名 ON 表名 REBUILD; -- MySQL ALTER TABLE 表名 ENGINE=InnoDB; -- 重建表(含索引) 或 OPTIMIZE TABLE 表名; -- 优化表(重建索引) ``` #### **2. 批量重建失效索引** - **Oracle**(重建所有UNUSABLE索引): ```sql BEGIN FOR idx IN (SELECT owner, index_name FROM dba_indexes WHERE status='UNUSABLE') LOOP EXECUTE IMMEDIATE 'ALTER INDEX ' || idx.owner || '.' || idx.index_name || ' REBUILD ONLINE'; END LOOP; END; / ``` - **SQL Server**(重建所有碎片化索引): ```sql DECLARE @SQL NVARCHAR(MAX) = ''; SELECT @SQL += 'ALTER INDEX ' + name + ' ON ' + OBJECT_NAME(object_id) + ' REBUILD; ' FROM sys.indexes WHERE avg_fragmentation_in_percent > 30; -- 碎片率>30%时重建 EXEC sp_executesql @SQL; ``` #### **3. 分区索引重建** ```sql -- Oracle(重建特定分区) ALTER INDEX 索引名 REBUILD PARTITION 分区名; -- SQL Server ALTER INDEX 索引名 ON 表名 REBUILD PARTITION = 分区号; ``` --- ### **二、自动化重建(维护计划)** #### **1. SQL Server 维护计划向导** 1. 打开 SSMS → 右键 **`管理`** → **`维护计划`** → **`维护计划向导`** 2. 命名计划 → 设置执行周期(如每周日凌晨) 3. 选择 **`重新生成索引`** 任务 → 配置数据库范围 4. 完成向导(自动生成作业)[^3] #### **2. Oracle 定时任务** ```sql BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'idx_rebuild_job', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN FOR idx IN (SELECT owner, index_name FROM dba_indexes WHERE status=''UNUSABLE'') LOOP EXECUTE IMMEDIATE ''ALTER INDEX '' || idx.owner || ''.'' || idx.index_name || '' REBUILD ONLINE''; END LOOP; END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=WEEKLY; BYDAY=SUN; BYHOUR=2', enabled => TRUE ); END; / ``` --- ### **三、关键注意事项** 1. **在线重建**: - 添加 **`ONLINE`** 选项(Oracle/SQL Server)可避免锁表,减少业务中断。 - 示例:`ALTER INDEX idx_name REBUILD ONLINE;` 2. **并行加速**: - 大表索引使用 **`PARALLEL`**(Oracle)或 **`MAXDOP`**(SQL Server): ```sql -- Oracle ALTER INDEX idx_name REBUILD PARALLEL 8; -- SQL Server ALTER INDEX idx_name ON 表名 REBUILD WITH (ONLINE=ON, MAXDOP=4); ``` 3. **空间与资源**: - 确保表空间有足够空间(Oracle 检查 `DBA_FREE_SPACE`)。 - 避免高峰时段操作,监控 CPU/I/O 使用率。 4. **重建前检查**: - 确认索引状态(`UNUSABLE` 或碎片率): ```sql -- Oracle 碎片检查 SELECT index_name, status FROM dba_indexes WHERE table_name='表名'; -- SQL Server 碎片检查 SELECT name, avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL); ``` --- ### **四、重建后验证** 1. **状态检查**: ```sql -- Oracle SELECT index_name, status FROM dba_indexes WHERE status='UNUSABLE'; -- 应返回空 -- SQL Server SELECT name, avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) WHERE avg_fragmentation_in_percent > 10; -- 碎片率应<10% ``` 2. **性能测试**: - 执行高频查询,对比重建前后的执行计划(如 `EXPLAIN PLAN`)。 --- ### **五、预防索引失效的建议** 1. **监控机制**: - 定期查询索引状态(如每日 Job)。 2. **避免高风险操作**: - `ALTER TABLE MOVE`(Oracle)、`TRUNCATE PARTITION` 后立即重建索引。 3. **统计信息维护**: - Oracle: `DBMS_STATS.GATHER_TABLE_STATS` - SQL Server: 开启 `AUTO_UPDATE_STATISTICS`[^1][^4] > **提示**:对于关键业务表,优先使用 **`ONLINE`** 重建。超大表建议分批操作(如按分区重建)。 --- ### 相关问题 1. 如何检测数据库索引的碎片化程度? 2. 在线重建索引(ONLINE)和离线重建的性能差异是什么? 3. 哪些操作会导致索引失效?如何避免? 4. 如何为海量表设计高效的索引维护策略? [^1]: 重建索引是提高数据库性能的重要手段,需结合监控和资源管理[^1]。 [^2]: 手动重建索引的语法示例[^2]。 [^3]: SQL Server 维护计划向导实现自动化重建[^3]。 [^4]: 索引创建前需检查表大小和列分布[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值