sql-server – 无法通过EF ExecuteSqlCommand重建索引

我有以下脚本来重建索引:

DECLARE @TableName VARCHAR(255)
DECLARE @sql NVARCHAR(500)
DECLARE @fillfactor INT

SET @fillfactor = 80

DECLARE TableCursor CURSOR FOR
    SELECT OBJECT_SCHEMA_NAME([object_id])+'.['+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

我有其他脚本以与此相同的方式运行.

当我以下列方式执行此操作时:

var sql = ResourceUtilities.ReadResourceContent("rebuild_indexes.sql");
db.Database.ExecuteSqlCommand(sql);

我收到以下错误:

Incorrect syntax near ‘TableCursor’.

ReadResourceContent的实现细节是无关紧要的 – 我正在运行其他任意SQL,它运行正常.

为什么会发生这种情况以及需要改变什么?

最佳答案 你应该至少尝试用分号终止所有行.虽然很少需要(我知道的只有两个实例是THROW语句之前的语句,这些语句是在SQL Server 2012和CTE之前引入的),但它在SQL Server 2005发布时被正式称为最佳实践.

使用分号终止语句/查询的好处之一是,当存在诸如不一致的行结尾之类的问题时,SQL Server将更容易解析查询批处理,这可能是此处问题的根本原因.我猜测根本原因是不一致的行结束,因为您可以通过SSMS对Azure数据库运行脚本.如果Azure SQL数据库上需要分号,那么即使通过SSMS运行也会产生错误.最有可能SSMS在提交批处理之前使得行结束一致,通过.NET代码运行的东西不会自动为您完成.

其他说明:

>最好不要混合VARCHAR和NVARCHAR(即使数据类型优先级最终会将它全部转换为NVARCHAR).由于您正在处理标识符(即表名称,数据库中的sysname类型,这是NVARCHAR(128)的别名),理想情况下,所有标识符都应为NVARCHAR,并且所有字符串文字都以N为前缀.
>在大多数情况下,特别是对于具有Identity列的表,FILLFACTOR为80是非常糟糕的,您应该使用100.当使用NEWID()然后从90开始并且仅在必要时降低.对于NEWSEQUENTIALID(),请使用100.
>在声明游标时,如果查询引用实际表而不是临时表,则使用STATIC关键字以便不锁定基表.并且通常使用以下关键字也是一个坏主意:LOCAL READ_ONLY FORWARD_ONLY.

最终结果应如下所示:

DECLARE @TableName sysname, -- system alias for NVARCHAR(128)
        @SQL NVARCHAR(500),
        @FillFactor TINYINT; -- value cannot be < 0 or > 100 anyway

SET @FillFactor = 100; -- or 90 if using NEWID() for Clustered Index

DECLARE TableCursor CURSOR STATIC LOCAL READ_ONLY FORWARD_ONLY
FOR
    SELECT OBJECT_SCHEMA_NAME(st.[object_id]) + N'.' + QUOTENAME(st.[name]) AS [TableName]
    FROM   sys.tables st;

OPEN TableCursor;

FETCH NEXT
FROM  TableCursor
INTO  @TableName;

WHILE (@@FETCH_STATUS = 0)
BEGIN
    SET @SQL = N'ALTER INDEX ALL ON '
               + @TableName
               + N' REBUILD WITH (FILLFACTOR = '
               + CONVERT(NVARCHAR(3), @FillFactor)
               + N')';

    EXEC (@SQL);

    FETCH NEXT
    FROM  TableCursor
    INTO  @TableName;
END;

CLOSE TableCursor;
DEALLOCATE TableCursor;
点赞