SQL Server中存储过程和触发器一般只会在初次编译时进行优化,之后如果相关的索引或数据库统计发生变化后,已编译的存储过程和触发器不会随之更新优化,可能会导致执行效率低下甚至失效,解决方法:
1、删除重新创建存储过程或触发器,也可以用ALTER方法代替
2、SQL Server提供了sp_recompile用于设置强制编译标识,存储过程或者触发器下次被使用的时候会先重新编译定制优化
3、在创建存储过程的时候使用WITH_RECOMPILE选项,指明不创建优化计划缓存,在每次执行之前都重新编译,但这个会导致存储过程执行数据缓慢;
类似,有时修改完表之后,与之关联视图也有可能不会自动刷新,导致出现一些奇观的问题,例如查询出来的数据列是错位的等,解决方法:
1、删除重新创建视图,也可以用ALTER方法提到
2、SQL Server提供了sp_refreshview方法强制刷新视图
为了自己方便,写了一个自动获取整个数据库中所有数据库实例中用户创建的的存储过程、触发器和视图进行强制刷新的SQL,可将其添加到数据库的JOB中周期执行:
--重新编译存储过程、触发器
use tempdb
go
--create temp table
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[gmcc_recompile_info]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
delete from gmcc_recompile_info
else
create table gmcc_recompile_info
(
dbname varchar(255),
objtype varchar(255),
objowner varchar(255),
objname varchar(255)
)
GO
--get all store procdure info
declare @dbname as varchar(255)
declare xx cursor for
select name from master.dbo.sysdatabases
open xx
fetch next from xx into @dbname
while @@fetch_status = 0
begin
exec('use [' + @dbname + '] insert into tempdb.dbo.gmcc_recompile_info select ''' + @dbname + ''', xtype, sysusers.name, sysobjects.name from sysobjects left join sysusers on sysobjects.uid=sysusers.uid where (xtype=''P'' or xtype=''TR'' or xtype=''V'') and category=0');
fetch next from xx into @dbname
end
close xx
DEALLOCATE xx
--set recompile
declare @objtype as varchar(255)
declare @objowner as varchar(255)
declare @objname as varchar(255)
declare yy cursor for
select dbname, objtype, objowner, objname from tempdb.dbo.gmcc_recompile_info
open yy
fetch next from yy into @dbname, @objtype, @objowner, @objname
while @@fetch_status = 0
begin
if @objtype='P' --storeprocedure
exec('use [' + @dbname + '] exec sp_recompile ''[' + @objowner + '].[' + @objname + ']''')
else if @objtype='TR' --trigger
exec('use [' + @dbname + '] exec sp_recompile ''[' + @objowner + '].[' + @objname + ']''')
else if @objtype='V' --view
exec('use [' + @dbname + '] exec sp_refreshview ''[' + @objowner + '].[' + @objname + ']''')
fetch next from yy into @dbname, @objtype, @objowner, @objname
end
close yy
DEALLOCATE yy
--drop temp table
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[gmcc_recompile_info]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table gmcc_recompile_info
GO
上述SQL存在两个问题尚未解决:
1、由于sp_refreshview刷新视图的及时执行的,如果由于数据库表发生变化,导致某个视图刷新失败的话,整个过程就会停止下来,导致后面的刷新不能进行;
2、不支持数据库名称包含中文的情况