Как удалить неверный план выполнения из базы данных SQL Azure?

12

DBCC FREEPROCCACHEне работает в Azure SQL DB. Как еще я могу заставить план выкинуть себя из кэша таким образом, чтобы это не повредило производственной системе (то есть я не могу просто изменять таблицы, как бы то ни было)? Это специально для SQL, созданного Entity Framework, так что это не хранимые процессы с самостоятельным управлением - это фактически динамический SQL.

(Источником были плохие показатели -> плохая статистика и т. Д. Все исправлено, но плохой план не исчезнет.)

ОБНОВЛЕНИЕ: я выбрал решение @ mrdenny, поскольку он добрался там сначала. Однако я успешно использую сценарий @Aaron Bertrand для выполнения работы. Спасибо всем за помощь !!

Jaxidian
источник
Можете ли вы сделать sp_recompile в Azure?
Мрденный
Да. На чем именно я бы его запустил? У нас нет сохраненных процедур. Это динамический SQL прибежал sp_executesql.
Джаксидиан
2
Вы можете запустить его на столе самостоятельно, и это должно очистить планы, которые используют эту таблицу. (Если это
сработает,
1
Я только что попробовал это на столе, и он, очевидно, блокирует таблицу в транзакции во время обработки. Я попробовал это на 10-колоночной таблице с 24 записями, и заняло больше минуты, чтобы закончить. За это время я не смог запросить таблицу. Я не могу запустить что-то подобное на наших реальных столах в Production!
Джаксидиан
1
Черт, это облом. Похоже, вам нужно будет изменить схему, например, добавить столбец, который можно обнулять, а затем удалить его. Это также сотрет кеш и должно быть быстрым. Тестирование точно скажет.
Мрденный

Ответы:

12

Azure SQL теперь напрямую поддерживает это

База данных SQL Azure напрямую поддерживает очистку кеш-памяти текущей базы данных пользователей без каких-либо взломов:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

Дополнительная информация

Следующий скрипт ( Шеннон Говен ) может быть использован для пошагового наблюдения за процессом:

-- run this script against a user database, not master
-- count number of plans currently in cache
select count(*) from sys.dm_exec_cached_plans;

-- Executing this statement will clear the procedure cache in the current database, which means that all queries will have to recompile.
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

-- count number of plans in cache now, after they were cleared from cache
select count(*) from sys.dm_exec_cached_plans;

-- list available plans
select * from sys.dm_exec_cached_plans;
Тодд менье
источник
Я еще не пробовал это, но если это на самом деле функционально, то это, вероятно, «лучший» ответ на начало 2017 года. Спасибо за это - я понятия не имел, что это было там! :-)
Джаксидиан
Я попробовал это (на Премиум БД), и это сработало.
Реми
Я пометил это как обновленный «Принятый ответ», но я еще не проверял это сам. Я основываю это непосредственно на отзывах Тодда и Реми. Спасибо всем!
Джаксидиан
Просто чтобы вернуться, я использовал это, и это работало хорошо для меня! Я добавляю несколько дополнительных сценариев к ответу Тодда, чтобы обогатить его, но его пост ударил по голове.
Джаксидиан
Кажется, это не работает для меня - он просто выполняется, но списки все еще полны - я нахожусь на SQL Azure - что может быть не так?
Дирк Бур
12

Сегодня нет явного способа сделать это, но это не постоянный сценарий (команда DBCC все еще не поддерживается, но читается в Query Store ). Даже если попадание изменения схемы является приемлемым, это может быть не тем, что вы хотите, потому что это сделает недействительными все планы, связанные с базовым объектом, а не только плохой.

Не нужно рассчитывать на это, но построить динамический SQL для выполнения одной и той же операции с несколькими таблицами довольно просто:

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER TABLE '
  + QUOTENAME(SCHEMA_NAME([schema_id])) 
  + '.' + QUOTENAME(name) + ' ADD fake_column INT NULL;
  ALTER TABLE ' 
  + QUOTENAME(SCHEMA_NAME([schema_id]))
  + '.' + QUOTENAME(name) + ' DROP COLUMN fake_column;'
FROM sys.tables
--WHERE name IN, LIKE, etc.

PRINT @sql;

-- if the command > 8K, you can see the second chunk e.g.

PRINT SUBSTRING(@sql, 8001, 8000);

--EXEC sys.sp_executesql @sql;

(Я написал совет об этой проблеме "длины динамического SQL" ...)

Аарон Бертран
источник
В моем случае, удалить их все гораздо предпочтительнее, чем оставить плохие там. Спасибо за внимание. Я знаю, что вы не можете рассказать мне о функциях, но можете ли вы сказать мне, когда вы можете больше не говорить о вещах, о которых не можете говорить? ;-)
Джаксидиан
Это также засекречено, извините. :-)
Аарон Бертран
Не уверен, что вы подразумеваете под ссылкой. Я имел в виду, что ваша nvarchar(max)переменная достигает предела после 4000 символов, 8000 символов, если я изменю его на varchar(max). Запуск этого точного сценария. У нас есть ~ 450 таблиц, поэтому мы можем легко их обработать (~ 30/60 таблиц в). varchar(max)допустимый синтаксис, он просто идентичен varchar(8000)и nvarchar(max)идентичен nvarchar(4000).
Джаксидиан
3
Ну да, когда вы PRINTкоманда, он показывает только 8000 байтов. Это ограничение PRINTкоманды, а не Azure. Если вы запустите команду, она будет работать, даже если вы не сможете визуально осмотреть все это.
Аарон Бертран
... дох, извини, я думаю ты прав! Спасибо, что поправили меня! Вот что происходит, когда твоя жена ожидала, что ты уйдешь 25 минут назад ... ;-) Этот сценарий отлично работает для меня!
Джаксидиан
6

Добавьте обнуляемый столбец в таблицу, затем отбросьте столбец. Это заставит SQL очистить кеш для этого объекта.

Что касается выполнения всех таблиц, курсор должен сделать свое дело. Просто используйте имя столбца, которое никогда не будет существовать ни в одной таблице, например, «zzzzzz_go_away» или что-то в этом роде.

mrdenny
источник
4

База данных SQL Azure в настоящее время не поддерживается DBCC FREEPROCCACHE, поэтому вы не можете вручную удалить план выполнения из кэша. Однако если вы внесете изменения в таблицу или представление, на которое ссылается запрос ( ALTER TABLE/ ALTER VIEW), план будет удален из кэша. ( Ссылка .)

Кин Шах
источник
Я уже знал все, что вы разместили здесь. Это не хранимая процедура и не представление, поэтому я не могу изменить одну из них. Как я могу изменить свои таблицы незначительным образом, находясь под нагрузкой и не вызывая простоев или блокировок таблицы, чтобы вызвать это?
Джаксидиан
1
Вы можете добавить фиктивный столбец и затем удалить его. Это удалит план из кэша. Насколько большой стол?
Кин Шах
В итоге это было решением, рекомендованным @mrdenny. Спасибо за помощь!! :-)
Jaxidian
1
Спасибо ... Всего несколько секунд не хватило времени .. Отвечал на какой-то другой пост на stackexchange ...
Кин Шах
1

Чтобы очистить весь план выполнения, используйте это:

    SET NOCOUNT ON

DECLARE @lcl_name VARCHAR(100)
DECLARE @addcolumnSql nVARCHAR(MAX)
DECLARE @dropcolumnSql nVARCHAR(MAX)

DECLARE cur_name CURSOR FOR
SELECT name
FROM sysobjects
WHERE type = 'U'
OPEN cur_name
FETCH NEXT FROM cur_name INTO @lcl_name
WHILE @@Fetch_status = 0
BEGIN
set @addcolumnSql = 'alter table [' + @lcl_name + '] add temp_col_to_clear_exec_plan bit'
EXEcute sp_executesql @addcolumnSql
print @addcolumnSql
set @dropcolumnSql = 'alter table [' + @lcl_name + '] drop column temp_col_to_clear_exec_plan'
EXEcute sp_executesql @dropcolumnSql
print @dropcolumnSql
--  EXEC (@lcl_name )
FETCH NEXT FROM cur_name INTO @lcl_name
END
CLOSE cur_name
DEALLOCATE cur_name
SET NOCOUNT OFF

Если вы изменяете таблицу или представление, ссылающиеся на нее, план выполнения очищается.

Немного более объяснено здесь http://christianarg.wordpress.com/2013/08/22/remove-execution-plans-from-the-procedure-cache-in-sql-azure/

Кристиан
источник