2017-01-05 9 views
4

У меня есть следующий сценарий для восстановления индексов:Не удается перестроить индексы с помощью 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 с этим и он отлично работает.

Почему это происходит и что нужно изменить?

+0

Что SQL Server версии вы выполнить это на? – ErikEJ

+0

a сторону: Хорошая практика - рассмотреть фрагментацию acutal перед вызовом перестройки – ErikEJ

+0

@ErikEJ - Azure SQL - и абсолютно. Это V1, где мы работаем каждые две недели, так как это приближается к частоте, на которой дефрагментация достигает уровней, требующих внимания. – SB2055

ответ

2

Вы должны хотя бы попытаться завершить все линии точкой с запятой. В редких случаях (только два экземпляра, о которых я знаю, относятся к операторам до THROW, которые были представлены в SQL Server 2012 и до CTE), он был официально отмечен как наилучший вариант выпуска SQL Server 2005.

Одним из преимуществ завершающих операторов/запросов с точками с запятой является то, что SQL Server будет легче анализировать партию запросов, если есть такие проблемы, как несогласованные строки-окончания, что, вероятно, является основной причиной проблемы здесь. Я предполагаю, что основная причина - несогласованность строк, поскольку вы можете запускать скрипт через SSMS против своей базы данных Azure. Если точки с запятой были требуются в базе данных Azure SQL, то это могло бы вызвать ошибку даже при работе через SSMS. Скорее всего, SSMS обеспечила согласованность строк перед отправкой пакета, что-то, что работает через .NET-код, не было бы автоматически для вас.

Другие ноты:

  • Было бы лучше, чтобы не смешивать VARCHAR и NVARCHAR (даже если Datatype Внеочередные будет конвертировать все это NVARCHAR в конце концов). Поскольку вы имеете дело с идентификаторами (например, именами таблиц, которые являются sysname, введите в базе данных, который является псевдонимом для NVARCHAR(128)), в идеале все должны быть NVARCHAR и все строковые литералы с префиксом N.

  • В большинстве случаев, особенно для таблиц столбца идентификации, FILLFACTOR 80 ужасен, и вы должны использовать 100. Whn с помощью 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; 
+1

Вы бы рекомендовали использовать 'QUOTENAME (st.name)' вместо 'N '. [' + St.name + N ']'' здесь? –

+0

@VladimirBaranov Я обычно не использую это, но опять же, я никогда не сталкивался с кем-то, вставляющим символ ']' в имя объекта ;-). Но да, хорошая идея. Я обновлю его. Благодаря :) –