最近在公司项目中使用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的执行计划缓存机制:

sp_executesql的执行计划会被重用

另外也有人建议使用DBCC FREEPROCCACHE清除sql server中所有缓存的执行计划来解决本文所述的问题(下面链接文章),但是DBCC FREEPROCCACHE这个语句对生产环境数据库的性能影响极大,不建议轻易使用!

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=89821

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.的更多相关文章

  1. 在sql server中怎样获得正在执行的Sql查询

    方法1:使用DBCC inputbuffer(spid) 使用SP_WHO获得SPID,然后再执行上面的DBCC command,参见下图 执行一段sql语句 打开另一个query窗口并执行SP_WH ...

  2. sql server 2008 R2无法连接127.0.0.1报错 Server error:40(错误:53)

    在公司用sql server 2008 R2很好的,回家连接127.0.0.1就报错.sql server2008R2主机名和.都可以登录,连接127.0.0.1出错,在与 SQL Server 建立 ...

  3. CentOS 7在执行yum操作时 报错

    CentOS 7在执行yum操作时, 报错:Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=6&arch ...

  4. 在caffe中执行脚本文件时 报错:-bash: ./train.sh: Permission denied

    报错原因:没有权限 解决方法:chmod 777 train.sh获得权限

  5. 优化SQL Server的内存占用之执行缓存

    在论坛上常见有朋友抱怨,说SQL Server太吃内存了.这里笔者根据经验简单介绍一下内存相关的调优知识   首先说明一下SQL Server内存占用由哪几部分组成.SQL Server占用的内存主要 ...

  6. ms sql server 在cmd中执行sqlcmd的时候报错

    cmd下直接输入sqlcmd会提示 错误: HResult 0x2,级别 16,状态 1命名管道提供程序: 无法打开与 SQL Server 的连接 [2].Sqlcmd: 错误: Microsoft ...

  7. Sql Server 带参数的存储过程执行方法

    Sql Server 带参数的存储过程执行方法 Visual C# 动态操作 SQL Server 数据库实例教程(4):带参数的存储过程执行方法 上一篇文章介绍了带参数的SQL语句执行方法和不带参数 ...

  8. SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总

    SQL Server游标   转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...

  9. SQL Server 2008空间数据应用系列三:SQL Server 2008空间数据类型

    原文:SQL Server 2008空间数据应用系列三:SQL Server 2008空间数据类型 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server ...

随机推荐

  1. postgresql逻辑结构--索引(六)

    一.索引简介 二.索引分类 三.创建索引 四.修改索引 五.删除索引

  2. div或其他html控件的overflow使用滚动条

    在编写html代码时, 有时候不想把控件撑大,滚动条就是个不错的选择 如下代码 <div style="height:auto !important;max-height:58px;o ...

  3. 15天学习MVC后的小结(分享经历与想法)

    学习MVC已经有半个月,看了看日历,刚好半个月.分享了好几篇练习的博文:一,<创建第一个MVC应用程序> http://www.cnblogs.com/insus/p/3358560.ht ...

  4. C++中的 CONST 含义(从#define 到 CONST 的转变)

    const 与define 两者都可以用来定义常量,但是const定义时,定义了常量的类型,所以更精确一些.#define只是简单的文本替换,除了可以定义常量外,还可以用来定义一些简单的函数,有点类似 ...

  5. Mac 自带的Apache php 狼神的

    开启服务:sudo /usr/sbin/apachectl start 停止服务:sudo /usr/sbin/apachectl stop 重启服务:sudo /usr/sbin/apachectl ...

  6. Docker的下载与安装

    一丶下载 1.win10之外的 Docker下载地址: https://www.docker.com/products/docker-toolbox 2.win10 Docker下载地址: https ...

  7. 字符串按首字母分组并ToDictionary的实现

    这是一道面试题目,要求实现字符串按首字母分组并ToDictionary输出,当时没有做出来,后面研究了一下,现在将这道题的几种实现方式记录下来. 首先初始化数据源,是一个List<string& ...

  8. Java - "JUC" ReentrantReadWriteLock

    Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock ReadWriteLock 和 ReentrantReadWriteLock介绍 ReadWriteLo ...

  9. Java虚拟机 - 类初始化

    [深入Java虚拟机]之三:类初始化 类初始化是类加载过程的最后一个阶段,到初始化阶段,才真正开始执行类中的Java程序代码.虚拟机规范严格规定了有且只有四种情况必须立即对类进行初始化: 遇到new. ...

  10. JS中的倒计时

    一.注:一般倒计时的时间都是后台传来的然后渲染到页面,这里有2个简单的倒计时方式 //带天数的倒计时function countDown(times){ var timer=null; timer=s ...