无法通过 EF ExecuteSqlCommand 重建索引
Can't rebuild indexes via 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 服务器在出现行尾不一致等问题时更容易解析查询批处理,这可能是根本原因这里的问题。我猜根本原因是行尾不一致,因为您可以通过 SSMS 针对您的 Azure 数据库 运行 脚本。如果 Azure SQL 数据库需要分号,那么即使在通过 SSMS 运行ning 时也会产生错误。 SSMS 很可能在提交批处理之前使行尾保持一致,运行通过 .NET 代码不会自动为您完成的事情。
其他说明:
最好不要混合使用 VARCHAR
和 NVARCHAR
(尽管数据类型优先级最终会将其全部转换为 NVARCHAR
)。由于您正在处理标识符(即 table 名称,它们在数据库中是 sysname
类型,是 NVARCHAR(128)
的别名),理想情况下所有都应该是 NVARCHAR
并且所有以 N
.
为前缀的字符串文字
在大多数情况下,尤其是对于带有标识列的 table,FILLFACTOR
80 是很糟糕的,您应该使用 100。当使用 NEWID()
然后从 90 开始,仅在必要时降低。对于 NEWSEQUENTIALID()
使用 100.
声明游标时,如果查询引用的是真实的tables而不是临时的tables,则使用STATIC
关键字以免锁定基数 table(s)。 通常也使用以下关键字是个不错的主意: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;
我有以下重建索引的脚本:
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 服务器在出现行尾不一致等问题时更容易解析查询批处理,这可能是根本原因这里的问题。我猜根本原因是行尾不一致,因为您可以通过 SSMS 针对您的 Azure 数据库 运行 脚本。如果 Azure SQL 数据库需要分号,那么即使在通过 SSMS 运行ning 时也会产生错误。 SSMS 很可能在提交批处理之前使行尾保持一致,运行通过 .NET 代码不会自动为您完成的事情。
其他说明:
最好不要混合使用
VARCHAR
和NVARCHAR
(尽管数据类型优先级最终会将其全部转换为NVARCHAR
)。由于您正在处理标识符(即 table 名称,它们在数据库中是sysname
类型,是NVARCHAR(128)
的别名),理想情况下所有都应该是NVARCHAR
并且所有以N
. 为前缀的字符串文字
在大多数情况下,尤其是对于带有标识列的 table,
FILLFACTOR
80 是很糟糕的,您应该使用 100。当使用NEWID()
然后从 90 开始,仅在必要时降低。对于NEWSEQUENTIALID()
使用 100.声明游标时,如果查询引用的是真实的tables而不是临时的tables,则使用
STATIC
关键字以免锁定基数 table(s)。 通常也使用以下关键字是个不错的主意: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;