更新服务器中所有数据库所有表的统计信息

Mar*_*lli 3 sql-server statistics index-statistics

嗨,我一直在编写一个脚本来更新我所有数据库上所有表的统计信息。这个想法是稍后对其进行参数化,但作为一个快速解决方案,今天不想实施Ola 的脚本,请按照下面的脚本进行操作。

我已经在几台服务器上对其进行了测试,但在我安排它在周日早上在实时服务器上运行之前,想获得一些想法并与您分享。

SET NOCOUNT ON

DECLARE @DBS TABLE (I INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED,
                    DBNAME SYSNAME NOT NULL )

DECLARE @I INT
        ,@Z INT
        ,@SQL VARCHAR(1008) 
        ,@j INT
        ,@Y INT
        ,@MYDB SYSNAME

INSERT INTO @DBS
SELECT s.name 
FROM sys.databases s
INNER JOIN SYS.master_files F ON S.DATABASE_ID = F.database_id  AND F.data_space_id = 1
WHERE S.STATE = 0 -- online
  AND S.database_id > 3 -- exclude master, tempdb and model -- I left msdb 
  AND S.is_read_only = 0 -- read/write
  AND S.user_access = 0 -- multi_user
  AND S.NAME NOT IN ('TableBackups',
                     'Troubleshooting')
ORDER BY F.SIZE DESC


SELECT @Z = @@ROWCOUNT
SELECT @I = 1



WHILE @I <= @z BEGIN


    BEGIN TRY DROP TABLE #T END TRY BEGIN CATCH END CATCH
    CREATE TABLE #T( I INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, MYSQL VARCHAR(1008) NOT NULL )

    SELECT @MYDB = QUOTENAME (S.DBNAME )
           ,@SQL = 'USE ' + QUOTENAME (S.DBNAME ) + ';' + CHAR(13) + ' 
                    ' + CHAR(13) +
                   'INSERT INTO #T(MYSQL)  SELECT ''UPDATE STATISTICS '' + QUOTENAME(NAME) FROM SYS.TABLES WHERE TYPE = ''U'' ' + CHAR(13)  

      FROM @DBS s
        WHERE s.I = @I 


    PRINT CAST (@SQL AS NTEXT)
       BEGIN TRY

            EXEC (@SQL)
            SELECT @Y = @@ROWCOUNT

       END TRY
       BEGIN CATCH
           SELECT @Y = 0
       END CATCH



    SELECT @J = 1

    WHILE @J <= @y BEGIN

       SELECT @SQL = 'USE ' + @MYDB + ';' + CHAR(13) + MYSQL 
       FROM #T 
       WHERE I= @J

       BEGIN TRY

            EXEC (@SQL)

       END TRY
       BEGIN CATCH
       END CATCH


       PRINT CAST (@SQL AS NTEXT)

       SELECT @J = @J + 1

    END 

    SELECT @I = @I +1

END /*WHILE*/
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

马上,您的脚本将完全忽略架构,因此它会失败,除非您的所有生产服务器仅dbo显式用作所有表的命名空间(并且没有人拥有除 之外的默认架构dbo)。您NTEXT似乎也无缘无故地使用了已弃用的数据类型 ( )。此外,我不认为WHERE针对 sys.tables的条款是必要的(我不知道除了 a 之外U还有什么)。不知道你为什么要按文件大小排序;如果您首先处理最大的数据库,则该作业不会完成得更快(如果data_space_id = 1.

最后,我想知道盲目更新整个实例中每个数据库中每个表的统计信息是否真的明智,无论大小如何......以及为什么您不费心检查索引视图,这也需要维护。如果添加一些逻辑来排除任何不需要的表,则可以节省大量工作。

我的部分解决方案

这段代码会稍微难以维护,没有TRY/CATCH你的包装器,也没有添加任何关于实际追求哪些表的额外逻辑,但是因为我从动态 SQL 中获得自动化任务(和真的很喜欢在这个网站上没有水平或垂直滚动​​条的解决方案),给你。当您对输出感到满意时,请注释打印并取消注释 exec。

DECLARE @sql NVARCHAR(MAX) = N'', @stats NVARCHAR(MAX) = N'';

SELECT @sql += N'EXEC ' + QUOTENAME(name) + '.sys.sp_executesql @stats;'
  FROM sys.databases 
  WHERE [state] = 0 AND user_access = 0; -- and your other filters

SET @stats = N'DECLARE @inner NVARCHAR(MAX) = N''''; 
  SELECT @inner += CHAR(10) + N''UPDATE STATISTICS '' 
    + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name) + '';'' 
    FROM sys.tables AS t
    INNER JOIN sys.schemas AS s 
    ON t.[schema_id] = s.[schema_id];
  PRINT CHAR(10) + DB_NAME() + CHAR(10) + @inner;
  --EXEC sys.sp_executesql @inner;'

EXEC [master].sys.sp_executesql @sql, N'@stats NVARCHAR(MAX)', @stats;
Run Code Online (Sandbox Code Playgroud)

  • 现在这是一些令人印象深刻的动态 SQL。 (2认同)