Sql server在使用sp_executesql @sql执行文本sql时,报错: Could not find database ID 16, name '16'. The database may be offline. Wait a few minutes and try again.
最近在公司项目中使用exec sp_executesql @sql执行一段文本sql的时候老是报错: Could not find database ID 16, name '16'. The database may be offline. Wait a few minutes and try again.执行的sql大概如下,注意其中有个额外的参数@databaseName是nvarchar类型,用来声明数据库的名字:
SET @tableScript=N''+ N'IF (SELECT COUNT(1) FROM ['+@databaseName+N'].dbo.sysobjects WHERE ID = OBJECT_ID(''['+@databaseName+N'].[dbo].[Raw_Tables_Metadata]''))=0 BEGIN CREATE TABLE ['+@databaseName+N'].[dbo].[Raw_Tables_Metadata]( ID INT IDENTITY(1,1) NOT NULL, Table_Name NVARCHAR(100) NOT NULL, Column_Name NVARCHAR(100) NOT NULL, Column_Type NVARCHAR(100) NOT NULL, Column_Size NVARCHAR(100) NULL, Skip_Rows INT NULL, CONSTRAINT [PK_Raw_Tables_Metadata] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] END' EXEC sp_executesql @tableScript;
后来我查找了master.dbo.sysdatabases这个系统表:
select * from master.dbo.sysdatabases
发现dbid为16的数据库现在在sql server中不存在。我就纳闷了,明明我在上面sql文本中的参数@databaseName中声明的是数据库'A',执行上面语句后,为啥现在sql server报错说一个不存在的数据库id是offline的。。。后来在网上查了查,发现这有可能是因为sp_executesql这个执行sql文本的系统存储过程会复用缓存的执行计划。我才想起数据库'A'在sql server中前几天被删除重建过,在删除前'A'的dbid是16,而重建后数据库'A'的dbid不是16了,现在dbid为16的数据库在sql server中不存在。。。然而由于sql server中缓存的执行计划没有被更新,所以执行上面语句后,sql server还是会复用老的执行计划,去通过dbid=16来查找数据库'A',最后导致报错。
后来我将上面的语句做了下小小的改动,仅仅是在exec sp_executesql @sql的后面加上了with recompile关键字,如下所示:
SET @tableScript=N''+ N'IF (SELECT COUNT(1) FROM ['+@databaseName+N'].dbo.sysobjects WHERE ID = OBJECT_ID(''['+@databaseName+N'].[dbo].[Raw_Tables_Metadata]''))=0 BEGIN CREATE TABLE ['+@databaseName+N'].[dbo].[Raw_Tables_Metadata]( ID INT IDENTITY(1,1) NOT NULL, Table_Name NVARCHAR(100) NOT NULL, Column_Name NVARCHAR(100) NOT NULL, Column_Type NVARCHAR(100) NOT NULL, Column_Size NVARCHAR(100) NULL, Skip_Rows INT NULL, CONSTRAINT [PK_Raw_Tables_Metadata] PRIMARY KEY CLUSTERED ( [ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] END' EXEC sp_executesql @tableScript with recompile;
加上with recompile后,exec sp_executesql @sql就不会重用系统中缓存的执行计划了,每次都是重新生成执行计划。不过这样做性能肯定是要低一些,但是至少保证了在我说的这个场景下不会出错。
所以在使用exec sp_executesql @sql的时候要小心,考虑缓存的执行计划被重用的可能性,另外可以参考下面这篇文章了解sp_executesql的执行计划缓存机制:
另外也有人建议使用DBCC FREEPROCCACHE清除sql server中所有缓存的执行计划来解决本文所述的问题(下面链接文章),但是DBCC FREEPROCCACHE这个语句对生产环境数据库的性能影响极大,不建议轻易使用!
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=89821
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2017-04-08 SQL Server中数据库文件的存放方式,文件和文件组 (转载)