0
点赞
收藏
分享

微信扫一扫

SQL Server、Oracle 如何清除指定SQL的执行计划


一、 SQL Server

1. 存储过程

如果是存储过程,可以使用sp_recompile指定存储过程名重新编译。

注意如果里面的参数是表名,那么所有用到该表的存储过程和trigger都会重新编译,谨慎操作。

-- 参数是存储过程名
USE AdventureWorks;
GO
EXEC sp_recompile N'myproc';
GO
-- 参数是表名
USE AdventureWorks;
GO
EXEC sp_recompile N'mytable';
GO

2. 一般sql

如果是一般的语句,比如

use AdventureWorks
go
SELECT * FROM Sales.SalesOrderHeader h, Sales.Customer c,Sales.SalesTerritory t
WHERE h.CustomerID = c.CustomerID
AND c.TerritoryID = t.TerritoryID
AND CountryRegionCode = N'CA';

可以先找到其plan_handle

SELECT usecounts,text,plan_handle,* FROM sys.dm_exec_cached_plans cp
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle)
CROSS APPLY sys.dm_exec_sql_text (cp.plan_handle)
where textlike
'%SELECT * FROM Sales.SalesOrderHeader h, Sales.Customer c,Sales.SalesTerritory t
WHERE h.CustomerID = c.CustomerID
AND c.TerritoryID = t.TerritoryID
AND CountryRegionCode%';

然后根据版本不同,清除操作也有所不同

① SQL Server 2008 R2及以上

直接使用DBCC FREEPROCCACHE然后传入plan_handle即可

DBCC FREEPROCCACHE(0x060001002903DC0B4001B887000000000000000000000000)

② SQL Server 2008 R2以下

SQL Server 2005的FREEPROCCACHE并不支持带参数,只能运行DBCC FREEPROCCACHE清空所有缓存,这对性能的影响比较大。有没有其他方法只清除特定的语句的缓存呢?

有的,答案就是使用plan guide

sp_create_plan_guide
@name =  N'recompile_Guide',
@stmt =
N'SELECT * FROM Sales.SalesOrderHeader h, Sales.Customer c,Sales.SalesTerritory t
WHERE h.CustomerID = c.CustomerID
AND c.TerritoryID = t.TerritoryID
AND CountryRegionCode = N''CA'';',
@type = N'SQL',
@module_or_batch =NULL,
@params =NULL,
@hints = N'OPTION (RECOMPILE)'
go
exec sp_control_plan_guide N'drop',N'recompile_Guide'

上面的sp_create_plan_guide使用RECOMPILE参数,意思是说,每次碰到该语句,必须重新编译。sp_create_plan_guide运行后,该语句的执行计划缓存就被删除了,下次该语句再次执行就会重新编译。那么我为什么马上又删除这个plan guide呢?因为该语句的缓存被清除后,我不希望该语句每次执行都重新编译,毕竟我执行sp_create_plan_guide的目的是删除该语句的执行计划缓存而已。所以如果你使用同样的手段,务必记得立即把sp_create_plan_guide建立的guide删除。

3. 清除指定数据库所有执行计划

2016之前有一个非公开的方法

DBCC FLUSHPROCINDB(db_id)

2016开始,正式提供了sql,支持清除指定数据库所有执行计划

ALTER DATABASE dnname CONFIGURATION CLEAR PROCEDURE_CACHE Criteria for plan reuse;

二、 Oracle

Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷出特定对象,例如游标,包,序列,触发器等。也就是说可以删除、清理特定SQL的执行计划。避免你为了刷新一个sql执行计划将整个SHARED POOL清空的危险情况。可以在$ORACLE_HOME/rdbms/admin/dbmspool.sql中查看该包的具体定义

PURGE存储过程有三个参数:

DBMS_SHARED_POOL.PURGE (
   name    VARCHAR2, 
   flag    CHAR DEFAULT 'P', 
   heaps   NUMBER DEFAULT 1);
 
Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 NAME                           VARCHAR2                IN
 FLAG                           CHAR                    IN     DEFAULT
 HEAPS                          NUMBER                  IN     DEFAULT

  • NAME:为逗号分隔的ADDRESS列和HASH_VALUE列的值。
  • FLAGS:可以有多个选项,清除sql执行计划填C,具体意义如下所示:

SQL Server、Oracle 如何清除指定SQL的执行计划_清理

  •  HEAPS:一般使用默认值1,清理整个对象

Heaps to be purged. For example, if heap 0 and heap 6 are to be purged:

1<<0 | 1<<6 => hex 0x41 => decimal 65, so specify heaps =>65.Default is 1, that is, heap 0 which means the whole object would be purged

清理指定sql语句执行计划方法如下:

col SQL_TEXT format a35
col ADDRESS format a18
col HASH_VALUE format a10
select s.SQL_TEXT, s.ADDRESS, s.HASH_VALUE||'' from v$sqlarea s where sql_id='xxxx';

SQL_TEXT                             ADDRESS           S.HASH_VALUE||''
----------------------------------- ------------------ --------------------------------
select /*gg*/count(*) from test     0000000300B06D70   728448230

--清除该sql执行计划
exec sys.dbms_shared_pool.purge('0000000300B06D70,728448230','c');

-- 再次查询,一般无输出结果,除非sql执行频率特别高
select s.SQL_TEXT, s.ADDRESS, s.HASH_VALUE||'' from v$sqlarea s where sql_id='xxxx';

参考

如何清除特定语句的执行计划缓存_51CTO博客_oracle清除执行计划缓存

ORACLE从共享池删除指定SQL的执行计划 - 潇湘隐者

Oracle 11g如何清除share pool中某条SQL的执行计划_深圳gg的博客-oracle flush share pool

举报

相关推荐

0 条评论