我有以下脚本来重建索引:
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);
我收到以下错误:
'TableCursor'附近的语法不正确。
ReadResourceContent
的实现细节是无关紧要的 - 我正在运行其他任意SQL,它运行正常。
为什么会发生这种情况以及需要改变什么?
答案 0 :(得分:2)
您至少应尝试使用分号终止所有行。虽然很少需要(我知道的只有两个实例是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
。
在大多数情况下,特别是对于具有标识列的表,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;