【问题标题】:Rebuild all indexes in a Database重建数据库中的所有索引
【发布时间】:2015-12-06 23:17:40
【问题描述】:

我有一个非常大的 SQL Server 2008 R2 数据库 (1.5TB),并且将在同一个表中从一列到另一列复制一些数据。我被告知架构有大量索引,并且想知道是否有默认查询或脚本可以重建所有索引。是否也被告知同时更新统计数据?

30 个表中的每一个都有一个聚集索引和 13 个非聚集索引

谢谢。

【问题讨论】:

标签: sql sql-server indexing sql-server-2008-r2


【解决方案1】:

也是一个不错的脚本,虽然我的笔记本电脑内存不足,但这是在一张非常大的桌子上

https://basitaalishan.com/2014/02/23/rebuild-all-indexes-on-all-tables-in-the-sql-server-database/

USE [<mydatabasename>]
Go

--/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
--Arguments             Data Type               Description
--------------          ------------            ------------
--@FillFactor           [int]                   Specifies a percentage that indicates how full the Database Engine should make the leaf level
--                                              of each index page during index creation or alteration. The valid inputs for this parameter
--                                              must be an integer value from 1 to 100 The default is 0.
--                                              For more information, see http://technet.microsoft.com/en-us/library/ms177459.aspx.

--@PadIndex             [varchar](3)            Specifies index padding. The PAD_INDEX option is useful only when FILLFACTOR is specified,
--                                              because PAD_INDEX uses the percentage specified by FILLFACTOR. If the percentage specified
--                                              for FILLFACTOR is not large enough to allow for one row, the Database Engine internally
--                                              overrides the percentage to allow for the minimum. The number of rows on an intermediate
--                                              index page is never less than two, regardless of how low the value of fillfactor. The valid
--                                              inputs for this parameter are ON or OFF. The default is OFF.
--                                              For more information, see http://technet.microsoft.com/en-us/library/ms188783.aspx.

--@SortInTempDB         [varchar](3)            Specifies whether to store temporary sort results in tempdb. The valid inputs for this
--                                              parameter are ON or OFF. The default is OFF.
--                                              For more information, see http://technet.microsoft.com/en-us/library/ms188281.aspx.

--@OnlineRebuild        [varchar](3)            Specifies whether underlying tables and associated indexes are available for queries and data
--                                              modification during the index operation. The valid inputs for this parameter are ON or OFF.
--                                              The default is OFF.
--                                              Note: Online index operations are only available in Enterprise edition of Microsoft
--                                                      SQL Server 2005 and above.
--                                              For more information, see http://technet.microsoft.com/en-us/library/ms191261.aspx.

--@DataCompression      [varchar](4)            Specifies the data compression option for the specified index, partition number, or range of
--                                              partitions. The options  for this parameter are as follows:
--                                                  > NONE - Index or specified partitions are not compressed.
--                                                  > ROW  - Index or specified partitions are compressed by using row compression.
--                                                  > PAGE - Index or specified partitions are compressed by using page compression.
--                                              The default is NONE.
--                                              Note: Data compression feature is only available in Enterprise edition of Microsoft
--                                                      SQL Server 2005 and above.
--                                              For more information about compression, see http://technet.microsoft.com/en-us/library/cc280449.aspx.

--@MaxDOP               [int]                   Overrides the max degree of parallelism configuration option for the duration of the index
--                                              operation. The valid input for this parameter can be between 0 and 64, but should not exceed
--                                              number of processors available to SQL Server.
--                                              For more information, see http://technet.microsoft.com/en-us/library/ms189094.aspx.
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

-- Ensure a USE <databasename> statement has been executed first.

SET NOCOUNT ON;

DECLARE  @Version                           [numeric] (18, 10)
        ,@SQLStatementID                    [int]
        ,@CurrentTSQLToExecute              [nvarchar](max)
        ,@FillFactor                        [int]        = 100 -- Change if needed
        ,@PadIndex                          [varchar](3) = N'OFF' -- Change if needed
        ,@SortInTempDB                      [varchar](3) = N'OFF' -- Change if needed
        ,@OnlineRebuild                     [varchar](3) = N'OFF' -- Change if needed
        ,@LOBCompaction                     [varchar](3) = N'ON' -- Change if needed
        ,@DataCompression                   [varchar](4) = N'NONE' -- Change if needed
        ,@MaxDOP                            [int]        = NULL -- Change if needed
        ,@IncludeDataCompressionArgument    [char](1);

IF OBJECT_ID(N'TempDb.dbo.#Work_To_Do') IS NOT NULL
    DROP TABLE #Work_To_Do
CREATE TABLE #Work_To_Do
    (
      [sql_id] [int] IDENTITY(1, 1)
                     PRIMARY KEY ,
      [tsql_text] [varchar](1024) ,
      [completed] [bit]
    )

SET @Version = CAST(LEFT(CAST(SERVERPROPERTY(N'ProductVersion') AS [nvarchar](128)), CHARINDEX('.', CAST(SERVERPROPERTY(N'ProductVersion') AS [nvarchar](128))) - 1) + N'.' + REPLACE(RIGHT(CAST(SERVERPROPERTY(N'ProductVersion') AS [nvarchar](128)), LEN(CAST(SERVERPROPERTY(N'ProductVersion') AS [nvarchar](128))) - CHARINDEX('.', CAST(SERVERPROPERTY(N'ProductVersion') AS [nvarchar](128)))), N'.', N'') AS [numeric](18, 10))

IF @DataCompression IN (N'PAGE', N'ROW', N'NONE')
    AND (
        @Version >= 10.0
        AND SERVERPROPERTY(N'EngineEdition') = 3
        )
BEGIN
    SET @IncludeDataCompressionArgument = N'Y'
END

IF @IncludeDataCompressionArgument IS NULL
BEGIN
    SET @IncludeDataCompressionArgument = N'N'
END

INSERT INTO #Work_To_Do ([tsql_text], [completed])
SELECT 'ALTER INDEX [' + i.[name] + '] ON' + SPACE(1) + QUOTENAME(t2.[TABLE_CATALOG]) + '.' + QUOTENAME(t2.[TABLE_SCHEMA]) + '.' + QUOTENAME(t2.[TABLE_NAME]) + SPACE(1) + 'REBUILD WITH (' + SPACE(1) + + CASE
        WHEN @PadIndex IS NULL
            THEN 'PAD_INDEX =' + SPACE(1) + CASE i.[is_padded]
                    WHEN 1
                        THEN 'ON'
                    WHEN 0
                        THEN 'OFF'
                    END
        ELSE 'PAD_INDEX =' + SPACE(1) + @PadIndex
        END + CASE
        WHEN @FillFactor IS NULL
            THEN ', FILLFACTOR =' + SPACE(1) + CONVERT([varchar](3), REPLACE(i.[fill_factor], 0, 100))
        ELSE ', FILLFACTOR =' + SPACE(1) + CONVERT([varchar](3), @FillFactor)
        END + CASE
        WHEN @SortInTempDB IS NULL
            THEN ''
        ELSE ', SORT_IN_TEMPDB =' + SPACE(1) + @SortInTempDB
        END + CASE
        WHEN @OnlineRebuild IS NULL
            THEN ''
        ELSE ', ONLINE =' + SPACE(1) + @OnlineRebuild
        END + ', STATISTICS_NORECOMPUTE =' + SPACE(1) + CASE st.[no_recompute]
        WHEN 0
            THEN 'OFF'
        WHEN 1
            THEN 'ON'
        END + ', ALLOW_ROW_LOCKS =' + SPACE(1) + CASE i.[allow_row_locks]
        WHEN 0
            THEN 'OFF'
        WHEN 1
            THEN 'ON'
        END + ', ALLOW_PAGE_LOCKS =' + SPACE(1) + CASE i.[allow_page_locks]
        WHEN 0
            THEN 'OFF'
        WHEN 1
            THEN 'ON'
        END + CASE
        WHEN @IncludeDataCompressionArgument = N'Y'
            THEN CASE
                    WHEN @DataCompression IS NULL
                        THEN ''
                    ELSE ', DATA_COMPRESSION =' + SPACE(1) + @DataCompression
                    END
        ELSE ''
        END + CASE
        WHEN @MaxDop IS NULL
            THEN ''
        ELSE ', MAXDOP =' + SPACE(1) + CONVERT([varchar](2), @MaxDOP)
        END + SPACE(1) + ')'
    ,0
FROM [sys].[tables] t1
INNER JOIN [sys].[indexes] i ON t1.[object_id] = i.[object_id]
    AND i.[index_id] > 0
    AND i.[type] IN (1, 2)
INNER JOIN [INFORMATION_SCHEMA].[TABLES] t2 ON t1.[name] = t2.[TABLE_NAME]
    AND t2.[TABLE_TYPE] = 'BASE TABLE'
INNER JOIN [sys].[stats] AS st WITH (NOLOCK) ON st.[object_id] = t1.[object_id]
    AND st.[name] = i.[name]

SELECT @SQLStatementID = MIN([sql_id])
FROM #Work_To_Do
WHERE [completed] = 0

WHILE @SQLStatementID IS NOT NULL
BEGIN
    SELECT @CurrentTSQLToExecute = [tsql_text]
    FROM #Work_To_Do
    WHERE [sql_id] = @SQLStatementID

    PRINT @CurrentTSQLToExecute

    EXEC [sys].[sp_executesql] @CurrentTSQLToExecute

    UPDATE #Work_To_Do
    SET [completed] = 1
    WHERE [sql_id] = @SQLStatementID

    SELECT @SQLStatementID = MIN([sql_id])
    FROM #Work_To_Do
    WHERE [completed] = 0
END

【讨论】:

    【解决方案2】:

    试试下面的脚本:

    Exec sp_msforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER INDEX ALL ON ? REBUILD'
    GO
    

    还有

    我更喜欢(经过长时间的搜索)使用下面的脚本,它包含 @fillfactor 决定了每个叶级页面上的空间有多少百分比被数据填充。

    DECLARE @TableName VARCHAR(255)
    DECLARE @sql NVARCHAR(500)
    DECLARE @fillfactor INT
    SET @fillfactor = 80 
    DECLARE TableCursor CURSOR FOR
    SELECT QUOTENAME(OBJECT_SCHEMA_NAME([object_id]))+'.' + QUOTENAME(name) AS TableName
    FROM sys.tables
    OPEN TableCursor
    FETCH NEXT FROM TableCursor INTO @TableName
    WHILE @@FETCH_STATUS = 0
    BEGIN
    SET @sql = 'ALTER INDEX ALL ON ' + @TableName + ' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3),@fillfactor) + ')'
    EXEC (@sql)
    FETCH NEXT FROM TableCursor INTO @TableName
    END
    CLOSE TableCursor
    DEALLOCATE TableCursor
    GO
    

    欲了解更多信息,请查看以下链接:

    https://blog.sqlauthority.com/2009/01/30/sql-server-2008-2005-rebuild-every-index-of-all-tables-of-database-rebuild-index-with-fillfactor/

    如果您想检查数据库中索引的索引碎片,请尝试以下脚本:

    SELECT dbschemas.[name] as 'Schema',
    dbtables.[name] as 'Table',
    dbindexes.[name] as 'Index',
    indexstats.avg_fragmentation_in_percent,
    indexstats.page_count
    FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
    INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
    INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
    INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
    AND indexstats.index_id = dbindexes.index_id
    WHERE indexstats.database_id = DB_ID() AND dbtables.[name] like '%%'
    ORDER BY indexstats.avg_fragmentation_in_percent desc
    

    欲了解更多信息,请查看以下链接:

    http://www.schneider-electric.com/en/faqs/FA234246/

    【讨论】:

      【解决方案3】:

      Daniel's script 似乎是一个很好的包罗万象的解决方案,但即使是他也承认他的笔记本电脑内存不足。这是我想出的一个选项。我的程序基于 TechNet 上的Mohammad Nizamuddin's post。我添加了一个初始游标循环,它将所有数据库名称提取到一个临时表中,然后使用它从每个数据库中提取所有基表名称。

      如果您不想重新索引所有数据库,您可以选择传递您喜欢的填充因子并指定目标数据库。


      --===============================================================
      -- Name:  sp_RebuildAllIndexes
      -- Arguements:  [Fill Factor], [Target Database name]
      -- Purpose:  Loop through all the databases on a server and
      --           compile a list of all the table within them.
      --           This list is then used to rebuild indexes for
      --           all the tables in all the database.  Optionally,
      --           you may pass a specific database name if you only
      --           want to reindex that target database.
      --================================================================
      CREATE PROCEDURE sp_RebuildAllIndexes(
          @FillFactor     INT = 90,
          @TargetDatabase NVARCHAR(100) = NULL)
      AS
          BEGIN
              DECLARE @TablesToReIndex TABLE (
                  TableName VARCHAR(200)
              );
              DECLARE @DbName VARCHAR(50);
              DECLARE @TableSelect VARCHAR(MAX);
              DECLARE @DatabasesToIndex CURSOR;
      
              IF ISNULL( @TargetDatabase, '' ) = ''
                SET @DatabasesToIndex = CURSOR
                FOR SELECT NAME
                    FROM   master..sysdatabases
              ELSE
                SET @DatabasesToIndex = CURSOR
                FOR SELECT NAME
                    FROM   master..sysdatabases
                    WHERE  NAME = @TargetDatabase
      
              OPEN DatabasesToIndex
      
              FETCH NEXT FROM DatabasesToIndex INTO @DbName
      
              WHILE @@FETCH_STATUS = 0
                  BEGIN
                      SET @TableSelect = 'INSERT INTO @TablesToReIndex SELECT CONCAT(TABLE_CATALOG, ''.'', TABLE_SCHEMA, ''.'', TABLE_NAME) AS TableName FROM '
                                         + @DbName
                                         + '.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''base table''';
      
                      EXEC sp_executesql
                          @TableSelect;
      
                      FETCH NEXT FROM DatabasesToIndex INTO @DbName
                  END
      
              CLOSE DatabasesToIndex
      
              DEALLOCATE DatabasesToIndex
      
              DECLARE @TableName VARCHAR(255)
              DECLARE TableCursor CURSOR FOR
                  SELECT TableName
                  FROM   @TablesToReIndex
      
              OPEN TableCursor
      
              FETCH NEXT FROM TableCursor INTO @TableName
      
              WHILE @@FETCH_STATUS = 0
                  BEGIN
                      DBCC DBREINDEX(@TableName, ' ', @FillFactor)
      
                      FETCH NEXT FROM TableCursor INTO @TableName
                  END
      
              CLOSE TableCursor
      
              DEALLOCATE TableCursor
          END 
      

      【讨论】:

        【解决方案4】:

        替换下面查询中的“您的数据库名称”。

            DECLARE @Database NVARCHAR(255)   
            DECLARE @Table NVARCHAR(255)  
            DECLARE @cmd NVARCHAR(1000)  
        
            DECLARE DatabaseCursor CURSOR READ_ONLY FOR  
            SELECT name FROM master.sys.databases   
            WHERE name IN ('YOUR DATABASE NAME')  -- databases
            AND state = 0 -- database is online
            AND is_in_standby = 0 -- database is not read only for log shipping
            ORDER BY 1  
        
            OPEN DatabaseCursor  
        
            FETCH NEXT FROM DatabaseCursor INTO @Database  
            WHILE @@FETCH_STATUS = 0  
            BEGIN  
        
               SET @cmd = 'DECLARE TableCursor CURSOR READ_ONLY FOR SELECT ''['' + table_catalog + ''].['' + table_schema + ''].['' +  
               table_name + '']'' as tableName FROM [' + @Database + '].INFORMATION_SCHEMA.TABLES WHERE table_type = ''BASE TABLE'''   
        
               -- create table cursor  
               EXEC (@cmd)  
               OPEN TableCursor   
        
               FETCH NEXT FROM TableCursor INTO @Table   
               WHILE @@FETCH_STATUS = 0   
               BEGIN
                  BEGIN TRY   
                     SET @cmd = 'ALTER INDEX ALL ON ' + @Table + ' REBUILD' 
                     PRINT @cmd -- uncomment if you want to see commands
                     EXEC (@cmd) 
                  END TRY
                  BEGIN CATCH
                     PRINT '---'
                     PRINT @cmd
                     PRINT ERROR_MESSAGE() 
                     PRINT '---'
                  END CATCH
        
                  FETCH NEXT FROM TableCursor INTO @Table   
               END   
        
               CLOSE TableCursor   
               DEALLOCATE TableCursor  
        
               FETCH NEXT FROM DatabaseCursor INTO @Database  
            END  
            CLOSE DatabaseCursor   
            DEALLOCATE DatabaseCursor
        

        【讨论】:

          【解决方案5】:
          DECLARE @String NVARCHAR(MAX);
          USE Databse Name;
          SELECT @String
              =
          (
              SELECT 'ALTER INDEX [' + dbindexes.[name] + '] ON [' + db.name + '].[' + dbschemas.[name] + '].[' + dbtables.[name]
                     + '] REBUILD PARTITION = ALL WITH (DATA_COMPRESSION = PAGE);' + CHAR(10) AS [text()]
              FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
                  INNER JOIN sys.tables dbtables
                      ON dbtables.[object_id] = indexstats.[object_id]
                  INNER JOIN sys.schemas dbschemas
                      ON dbtables.[schema_id] = dbschemas.[schema_id]
                  INNER JOIN sys.indexes AS dbindexes
                      ON dbindexes.[object_id] = indexstats.[object_id]
                         AND indexstats.index_id = dbindexes.index_id
                  INNER JOIN sys.databases AS db
                      ON db.database_id = indexstats.database_id
              WHERE dbindexes.name IS NOT NULL
                    AND indexstats.database_id = DB_ID()
                    AND indexstats.avg_fragmentation_in_percent >= 10
              ORDER BY indexstats.page_count DESC
              FOR XML PATH('')
          );
          EXEC (@String);
          

          【讨论】:

            【解决方案6】:
            DECLARE @Database NVARCHAR(255)   
            DECLARE @Table NVARCHAR(255)  
            DECLARE @cmd NVARCHAR(1000)  
            
            DECLARE DatabaseCursor CURSOR READ_ONLY FOR  
            SELECT name FROM master.sys.databases   
            WHERE name NOT IN ('master','msdb','tempdb','model','distribution')  -- databases to exclude
            --WHERE name IN ('DB1', 'DB2') -- use this to select specific databases and comment out line above
            AND state = 0 -- database is online
            AND is_in_standby = 0 -- database is not read only for log shipping
            ORDER BY 1  
            
            OPEN DatabaseCursor  
            
            FETCH NEXT FROM DatabaseCursor INTO @Database  
            WHILE @@FETCH_STATUS = 0  
            BEGIN  
            
               SET @cmd = 'DECLARE TableCursor CURSOR READ_ONLY FOR SELECT ''['' + table_catalog + ''].['' + table_schema + ''].['' +  
               table_name + '']'' as tableName FROM [' + @Database + '].INFORMATION_SCHEMA.TABLES WHERE table_type = ''BASE TABLE'''   
            
               -- create table cursor  
               EXEC (@cmd)  
               OPEN TableCursor   
            
               FETCH NEXT FROM TableCursor INTO @Table   
               WHILE @@FETCH_STATUS = 0   
               BEGIN
                  BEGIN TRY   
                     SET @cmd = 'ALTER INDEX ALL ON ' + @Table + ' REBUILD' 
                     --PRINT @cmd -- uncomment if you want to see commands
                     EXEC (@cmd) 
                  END TRY
                  BEGIN CATCH
                     PRINT '---'
                     PRINT @cmd
                     PRINT ERROR_MESSAGE() 
                     PRINT '---'
                  END CATCH
            
                  FETCH NEXT FROM TableCursor INTO @Table   
               END   
            
               CLOSE TableCursor   
               DEALLOCATE TableCursor  
            
               FETCH NEXT FROM DatabaseCursor INTO @Database  
            END  
            CLOSE DatabaseCursor   
            DEALLOCATE DatabaseCursor
            

            【讨论】:

              猜你喜欢
              • 2014-10-10
              • 2012-02-23
              • 1970-01-01
              • 2018-08-24
              • 2013-03-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-09-11
              相关资源
              最近更新 更多