找回密码
 立即注册
首页 业界区 安全 数据库索引重组与重建

数据库索引重组与重建

阮蓄 2025-11-24 10:25:06
不久前,遇到了一个问题。一个普通的数据库查询出现了超时,表的数据量不多,不应该会出现超时的情况。
时间发生在凌晨,组长说应该DBA在执行索引重组与重建脚本。哦?这是什么我完全不知道,上百度!
什么是索引

索引大家应该都了解,索引的作用就像书的目录,可以让数据库在查询时更快定位数据,而不是整表扫描。

  • 提升查询效率
  • 加速排序和分组
  • 保证唯一性
什么是重组与重建索引呢?为什么要这么做?

索引不是一劳永逸的,它们会因为数据更新而“碎片化”:

  • 插入:可能在页中间插入新值,导致数据页分裂。
  • 删除:留下空洞。
  • 更新:可能把数据移到别的页。
这些操作时间长了会让索引的存储结构(B+树)效率下降。
所以DBA通常会定期重建索引或重组索引,来减少碎片、提高查询性能。
为什么多在凌晨执行

白天系统访问量大,重建索引会锁表/占用大量I/O和CPU,影响业务。
凌晨访问量小,适合做维护任务(索引重建、统计信息更新、备份)。
SQL脚本

知道了什么是重组与重建索引,就要理解如何实现该操作呢?
找Chatgpt写一个脚本,解析一下看看。
  1. --关闭行计数返回
  2. SET NOCOUNT ON;
  3. DECLARE @SchemaName NVARCHAR(256);  --变量模式
  4. DECLARE @TableName NVARCHAR(256);   --变量表名
  5. DECLARE @IndexName NVARCHAR(256);   --变量索引名
  6. DECLARE @AvgFrag DECIMAL(18,2);     --变量平均碎片率
  7. DECLARE @sql NVARCHAR(MAX);         --变量要执行的SQL字符串
  8. --判断是否已存在,先删后建
  9. IF OBJECT_ID('tempdb..#FragList') IS NOT NULL
  10.     DROP TABLE #FragList;
  11. --创建临时表
  12. CREATE TABLE #FragList
  13. (
  14.     ObjectId INT,
  15.     IndexId INT,
  16.     SchemaName NVARCHAR(256),
  17.     TableName NVARCHAR(256),
  18.     IndexName NVARCHAR(256),
  19.     AvgFragmentation DECIMAL(18,2),
  20.     PageCount BIGINT
  21. );
  22. --统计索引碎片率信息
  23. --sys.dm_db_index_physical_stats 获取当前数据库的索引物理统计
  24. INSERT INTO #FragList
  25. SELECT
  26.     ips.object_id,
  27.     ips.index_id,
  28.     s.name AS SchemaName,
  29.     t.name AS TableName,
  30.     i.name AS IndexName,
  31.     ips.avg_fragmentation_in_percent,
  32.     ips.page_count
  33. FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
  34. JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
  35. JOIN sys.tables t ON t.object_id = ips.object_id
  36. JOIN sys.schemas s ON t.schema_id = s.schema_id
  37. WHERE ips.database_id = DB_ID()
  38.   AND i.type_desc <> 'HEAP'
  39.   AND ips.page_count > 100; -- 可选:只处理较大的索引
  40. --游标批处理(等同于foreach),遍历#FragList
  41. DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
  42. SELECT SchemaName, TableName, IndexName, AvgFragmentation
  43. FROM #FragList;
  44. OPEN cur;
  45. FETCH NEXT FROM cur INTO @SchemaName, @TableName, @IndexName, @AvgFrag;
  46. WHILE @@FETCH_STATUS = 0
  47. BEGIN
  48.     SET @sql = NULL;
  49.     IF @AvgFrag BETWEEN 5 AND 30
  50.         SET @sql = N'ALTER INDEX [' + @IndexName + '] ON [' + @SchemaName + '].[' + @TableName + '] REORGANIZE;';
  51.     ELSE IF @AvgFrag > 30
  52.         SET @sql = N'ALTER INDEX [' + @IndexName + '] ON [' + @SchemaName + '].[' + @TableName + '] REBUILD WITH (ONLINE = ON);';
  53.     IF @sql IS NOT NULL
  54.     BEGIN
  55.         PRINT @sql;
  56.         EXEC sp_executesql @sql;
  57.     END
  58.     FETCH NEXT FROM cur INTO @SchemaName, @TableName, @IndexName, @AvgFrag;
  59. END
  60. CLOSE cur;
  61. DEALLOCATE cur;
  62. ```"
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

2025-11-30 18:14:21

举报

您需要登录后才可以回帖 登录 | 立即注册