更新索引和统计脚本

rax*_*xso 2 sql-server t-sql index-tuning

我在下面的脚本中遇到以下错误

消息 102,级别 15,状态 1,第 44 行
'?' 附近的语法不正确。

消息 319,级别 15,状态 1,第 47 行
关键字“with”附近的语法不正确。如果此语句是公共表表达式、xmlnamespaces 子句或更改跟踪上下文子句,则前一条语句必须以分号终止。

任何人都可以帮助解决这个问题,它似乎也没有围绕每个数据库

DECLARE @command    NVARCHAR(MAX)
CREATE TABLE #worktable
(
    [Database]  SYSNAME
    ,SchemaName SYSNAME
    ,ObjectName SYSNAME
    ,StatsName  SYSNAME
    ,ColName    SYSNAME
    --,Command  VARCHAR(500)
)

exec [master].[sys].sp_MSForEachDB @command1="use [?]"
INSERT INTO #worktable 
    SELECT 
        '[?]'                                               AS [Database]
        ,sch.[name]                                     AS [SchemaName]
        --,OBJECT_NAME(o.[object_id],DB_ID(''[?]''))            AS [ObjectName]
        ,o.[Name]                                       AS [ObjectName]
        ,s.name                                             AS [StatsName]
        ,c.name                                             AS [ColName]
        --,''COMMAND''                                      AS [Command]
        FROM sys.stats AS s

    INNER JOIN sys.stats_columns AS sc 
        ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id

    INNER JOIN sys.objects o
    INNER JOIN sys.schemas AS sch
        ON o.schema_id = sch.schema_id
        ON s.[object_id] = o.[object_id]
        AND o.is_ms_shipped = 0

    INNER JOIN sys.columns AS c 
        ON sc.object_id = c.object_id AND c.column_id = sc.column_id

select * from #worktable
drop table #worktable

exec [MASTER].[sys].sp_MSForEachDB 
INSERT INTO #worktable 
    SELECT  'Test'      AS [Database]
        ,OBJECT_SCHEMA_NAME(sch.name ,DB_ID(''[?]''))   AS [SchemaName]
        ,OBJECT_NAME(ss.[object_id],DB_ID(''[?]''))     AS [ObjectName]
        ,ss.[name]                          AS [StatsName]
        ,''UPDATE STATISTICS ''+''[?]''+''.''+OBJECT_SCHEMA_NAME(ss.[object_id],DB_ID(''[?]''))+''.''+OBJECT_NAME(ss.[object_id],DB_ID(''[?]''))+'' ''+ss.[name]+'' WITH FULLSCAN;'' AS Command

    FROM [?].sys.stats ss

    CROSS APPLY [?].sys.dm_db_stats_properties(ss.[object_id],ss.stats_id) sp

    WHERE   (           (sp.last_updated < DATEADD(hh,-6,GetDate()))
            OR      (sp.[modification_counter] > (0.1*sp.[rows]))
            OR      (sp.[rows_sampled] <> sp.[rows])
        )

    ORDER BY sp.[rows] ASC -- does the small stuff first, makes the difference earlier'

DECLARE cmdlist CURSOR FOR SELECT Command FROM #worktable

-- Open the cursor.
OPEN cmdlist

-- Loop through the partitions
WHILE (1=1)
   BEGIN
        FETCH NEXT FROM cmdlist
           INTO @command

        IF @@FETCH_STATUS < 0 BREAK

        --EXEC (@command);

        PRINT N'Executed: ' + @command
    END;

CLOSE cmdlist
DEALLOCATE cmdlist

DROP TABLE #worktable
GO
Run Code Online (Sandbox Code Playgroud)

Kin*_*hah 6

我诚实的意见是 - 不要重新发明轮子,因为重新发明它是有成本的

强烈建议您使用Ola 的索引和统计维护解决方案

它非常灵活,受到高度评价和测试。此外,它不使用脚本中的任何 ms_foreach 内容。


Ken*_*her 5

首先让我说,一般建议您不要使用 sp_msforeachdb。它有一些有据可查的缺陷,偶尔会错过数据库。@AaronBertrand 有一个他写版本要好得多。

其次,你似乎很早就切断了你的弦。您编写它的方式将像这样执行。

这部分将首先针对每个数据库执行:

exec [master].[sys].sp_MSForEachDB @command1="use [?]"
Run Code Online (Sandbox Code Playgroud)

然后这部分将针对您当前的数据库执行:

INSERT INTO #worktable 
    SELECT 
        '[?]'                                               AS [Database]
        ,sch.[name]                                     AS [SchemaName]
        --,OBJECT_NAME(o.[object_id],DB_ID(''[?]''))            AS [ObjectName]
        ,o.[Name]                                       AS [ObjectName]
        ,s.name                                             AS [StatsName]
        ,c.name                                             AS [ColName]
        --,''COMMAND''                                      AS [Command]
        FROM sys.stats AS s

    INNER JOIN sys.stats_columns AS sc 
        ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id

    INNER JOIN sys.objects o
    INNER JOIN sys.schemas AS sch
        ON o.schema_id = sch.schema_id
        ON s.[object_id] = o.[object_id]
        AND o.is_ms_shipped = 0

    INNER JOIN sys.columns AS c 
        ON sc.object_id = c.object_id AND c.column_id = sc.column_id
Run Code Online (Sandbox Code Playgroud)

我的猜测是,您确实希望代码的第一部分如下所示:

DECLARE @sql nvarchar(4000)

SET @SQL = N'use [?];
    INSERT INTO #worktable 
        SELECT 
            ''[?]''                                               AS [Database]
            ,sch.[name]                                     AS [SchemaName]
            --,OBJECT_NAME(o.[object_id],DB_ID(''[?]''))            AS [ObjectName]
            ,o.[Name]                                       AS [ObjectName]
            ,s.name                                             AS [StatsName]
            ,c.name                                             AS [ColName]
            --,''COMMAND''                                      AS [Command]
            FROM sys.stats AS s

        INNER JOIN sys.stats_columns AS sc 
            ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id

        INNER JOIN sys.objects o
        INNER JOIN sys.schemas AS sch
            ON o.schema_id = sch.schema_id
            ON s.[object_id] = o.[object_id]
            AND o.is_ms_shipped = 0

        INNER JOIN sys.columns AS c 
            ON sc.object_id = c.object_id AND c.column_id = sc.column_id'

exec [master].[sys].sp_MSForEachDB @SQL
Run Code Online (Sandbox Code Playgroud)

您在脚本的后半部分遇到了类似的问题。您想要声明一个变量,将您的命令放入其中,然后针对该变量运行 sp_MSForEachDB。通过这种方式,您可以先打印出您的变量,以确保您正在运行正确的命令。