如何从Azure SQL数据库中删除错误的执行计划?


12

DBCC FREEPROCCACHE在Azure SQL DB中不起作用。我还能如何强制计划以一种不会损害生产系统的方式将自己从缓存中踢出(即,我不能只是随意改变表)?这是专门针对由Entity Framework创建的SQL,因此它们不是自我管理的存储过程-它实际上是动态SQL。

(来源是错误的索引->错误的统计信息,等等。这些都是固定的,但是错误的计划不会消失。)

更新: 我选择了@mrdenny的解决方案,因为他先到达了那里。但是,我已经成功使用@Aaron Bertrand的脚本执行了工作。感谢大家的帮助!


您可以在Azure中执行sp_recompile吗?
mrdenny

是。我到底要运行什么?我们没有存储过程。这是运行中的动态SQL sp_executesql
Jaxidian

2
您可以在它自己的表上运行它,这应该刷新使用该表的计划。(如果这个方法有效,我会回答。)
mrdenny

1
我只是在表上尝试过,显然它在处理时将表锁定在事务中。我在只有24条记录的10列表上进行了尝试,花了一分钟才完成。在这段时间内,我无法查询该表。我不能在Production的实际表上运行类似的东西!
Jaxidian

1
该死的,真是令人讨厌。看起来您需要进行架构更改,例如添加可空列,然后将其删除。这也将清除缓存,并且应该很快。测试将确定。
mrdenny

Answers:


12

Azure SQL现在直接支持此功能

Azure SQL数据库直接支持清除当前用户数据库的proc缓存,而不会受到任何攻击:

ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;

附加信息

以下脚本(由Shannon Gowen撰写)可用于逐步观察过程:

-- 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年初,这可能是“最佳”答案。:-)
Jaxidian

我已经试过了(在Premium DB上),它奏效了。
Remi Lemarchand

我已将其标记为更新的“已接受答案”,但我自己尚未对此进行测试。我将直接基于Todd和Remi的反馈。谢谢大家!
Jaxidian

只是为了重新访问,我已经使用了它,它对我来说效果很好!我在此处为Todd的答案添加了一些其他脚本,以丰富其内容,但他的帖子触动了人们的头脑。
Jaxidian '17

这似乎对我不起作用-它只是执行但列表仍然满-我在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长度”问题的提示 ...)


以我为例,将所有这些都删除比将坏问题留在那儿要好得多。感谢您的注意。我知道您不能告诉我功能,但是您可以告诉我什么时候您可能不再被限制谈论无法谈论的事情吗?;-)
Jaxidian

那也属于机密,对不起。:-)
亚伦·伯特兰

不确定链接的含义。我的意思是,您的nvarchar(max)变量在4000个字符之后达到限制,如果将其更改为8000个字符varchar(max)。运行确切的脚本。我们有大约450张桌子,所以我们很容易达到(大约30/60张桌子)。varchar(max)是有效的语法,它与varchar(8000)nvarchar(max)相同nvarchar(4000)
Jaxidian

3
是的,当您PRINT输入命令时,它仅显示8000个字节。那是PRINT命令的限制,不是Azure。如果您运行该命令,即使您无法目视检查整个内容,它也将起作用。
亚伦·伯特兰

……对不起,我想你是对的!感谢您纠正我!当您的妻子希望您在25分钟前离开时,就会发生这种情况... ;-)这个脚本对我来说非常有效!
Jaxidian

6

将可空列添加到表中,然后删除该列。这将迫使SQL刷新该对象的缓存。

至于制作所有表,游标应该可以解决。只需使用在任何表(如“ zzzzzz_go_away”等)中都不存在的列名即可。


4

Azure SQL数据库当前不支持DBCC FREEPROCCACHE,因此您不能从缓存中手动删除执行计划。但是,如果您更改查询(ALTER TABLE/ ALTER VIEW)引用的表或视图,则该计划将从缓存中删除。(参考。)


我已经知道您在此处发布的所有内容。这既不是存储过程也不是视图,因此我无法修改其中之一。如何在负载下且不造成任何停机或表锁定的情况下以微不足道的方式修改表以触发此操作?
Jaxidian

1
您可以添加一个虚拟列,然后将其删除。这将从缓存中删除该计划。桌子多大?
Kin Shah

最终成为了@mrdenny建议的解决方案。谢谢您的帮助!!:-)
Jaxidian

1
谢谢...短短几秒钟..还在回答关于stackexchange的其他帖子...
Kin Shah

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/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.