存储过程中引用的常规表,临时表以及表变量是否会导致存储过程的重编译

在存储过程中,经常要引用一些表来存储一些中间数据,用完即删。对于这个中间表,用常规表,临时表或者表变量有什么区别呢?

下面我们看一下这三种中间表是否会造成执行计划的重编译。

首先打开sql server profile,监控存储过程。

1.建第一个存储过程,在存储过程中创建常规表TT1

CREATE PROCEDURE TEST1_PRO
AS
BEGIN
    CREATE TABLE TT1(
    ID INT IDENTITY,
    NAME VARCHAR(10)
    )

    INSERT INTO TT1
    VALUES (‘name1‘)

    select * From TT1

    DROP TABLE TT1
END

下面调用存储过程

--Firsttime
EXEC TEST1_PRO

查看sql server profile的如下截图:

可以看到在存储过程中创建常规表,会造成两次重编译。第一个编译是由于常规表的新建之后的DML操作造成的,第二个重编译是查询新建表导致的执行计划的编译。

下面我们第二次调用该存储过程

--SecondTime
EXEC TEST1_PRO

查看sql server profile的如下截图:

可以看到第二次调用存储过程跟第一次调用存储过程都会造成两次重编译。

2.建第二个存储过程,在存储过程中创建临时表#TT1

CREATE PROCEDURE TEST2_PRO
AS
BEGIN
    CREATE TABLE #TT1(
    ID INT IDENTITY,
    NAME VARCHAR(10)
    )

    INSERT INTO #TT1
    VALUES (‘name1‘)

    select * From #TT1
    DROP TABLE #TT1
END

调用存储过程

--Firsttime
EXEC TEST2_PRO

查看sql server profile的如下截图:

可以看到第一次调用TEST2_PRO存储过程跟第一次调用TEST1_PRO的时候造成的重编译是一样的,两次重编译。

我们再次调用该存储过程

--SecondTime
EXEC TEST2_PRO

查看sql server profile的如下截图:

可以看到当存储过程再次被执行时,没有发生重编译。临时表只能用于存储过程范围之内,无法在存储过程范围之外使用,因此其架构在多次执行之后并未发生任何改变,从而可以在存储过程后续执行期间重用现有的执行计划。

3.建第三个存储过程,在存储过程中创建表变量@TT1

CREATE PROCEDURE TEST3_PRO
AS
BEGIN
DECLARE @TT1 TABLE(
    ID INT IDENTITY,
    NAME VARCHAR(10)
    )

    INSERT INTO @TT1
    VALUES (‘name1‘)

    select * From @TT1

END

调用存储过程

--Firsttime
EXEC TEST3_PRO

查看sql server profile的如下截图:

可以看到对于存储过程中创建表变量,第一次调用该存储过程并没有发生重编译。

再次调用存储过程

--SecondTime
EXEC TEST3_PRO

查看sql server profile的如下截图:

再次调用存储过程之后,也没有发生重编译,可以看到当用表变量当存储过程的中间表,不会造成存储过程的重编译。

由于表变量不会写日志,不会造成锁开销,不能在Declare之外创建主键索引等,因此表变量不会造成架构的变化,从而不会造成重编译。该存储过程的执行计划已经在创建存储过程的时候生成了,因此之后执行的存储过程不会造成执行计划的重编译。

综上所述,我认为在存储过程中中间表需要存储少量数据时,创建表变量来存储中间数据是开销最小的。

如果大家有什么问题可以提出来,相互交流,谢谢!

时间: 2024-12-28 21:04:35

存储过程中引用的常规表,临时表以及表变量是否会导致存储过程的重编译的相关文章

sqlserver 存储过程中使用临时表到底会不会导致重编译

曾经在网络上看到过,SqlServer的存储过程中使用临时表,会导致执行计划无法重用, 运行时候会导致重编译的这么一个说法,自己私底下去做测试的时候,根据profile的跟踪结果, 如果不是统计信息变更导致导致的重编译,单单是使用临时表,并不会导致重编译, 但是对于一些特殊的情况,又确实会出现重编译的, 为了弄清楚这个问题,查阅了大量的资料,才把这个问题弄清楚,这里特意记录下来,希望武断地认为存储过程中使用了临时表就会导致重编译的这个观点得到纠正. 首先进行下面的测试,我们知道,导致临时表重编译

如何避免存储过程中不必要的重新编译?(一)

一.  使用存储过程有如下好处: 1. 使用存储过程可以对所执行的SQL语句进行封装,在接口保持不变的情况下不影响调用程序. 2. 最大限度的重用已缓存的执行计划. 3. 减少网络流量. 4. 提供更好的数据库安全控制,防止直接对表的操作. 存储过程的编译占用CPU,因此我们应该防止存储过程不必要的重新编译. 二.编译 (一)正常的编译发生于: 1. 所引用的表中大部分的数据发生了的更改,导致统计信息变化过大. 2. 所引用的表的架构被修改,包括添加或取消约束.默认值或规则. 3. 明确使用WI

数组 类型 在 存储过程中 使用

oracle 之定义数组类型 注:本文来源:<oracle 之定义数组类型 > oracle 数组类型,没有现成的类型,但是可以自己随意定义,很方便. Oracle 数组可以分为定长数组和可变长的数组两类.以下主要是一维数组介绍: 1:定长数组: 1 /*定长字符数组,数组大小为10*/ 2 declare 3 type v_arr is varray(10) of varchar2(30); 4 my_arr v_arr; 5 my_arr:=v_arr('1','2','3'); 6 be

(4.27)查看存储过程中的依赖关系

关键词:查看存储过程中引用的表,查看表在哪些存储过程中出现过 很多时候需要找到存储过程所依赖的对象.博客描述了一种在SQL服务器中查找存储过程依赖关系的方法. 以下查询创建存储过程. 1 2 3 4 5 6 7 8 9 10 11 IF object_id('usp_getpersonaddress') is not null drop proc usp_getpersonaddress GO Create procedure usp_getpersonaddress AS SELECT pp.

解决存储过程中拼接的SQL字符串超长导致sql语句被截取的问题

今天遇到了一个奇葩的问题:存储过程中的sql字符串拼接的太长,超出了分页存储过程执行sql参数的nvarchar(4000)的长度. 没办法,只能修改自己的存储过程,因为分页存储过程是不能动的. 开始想到的方法是将里层的select语句抽出来,用exec(strInnerSql)执行,将查询胡来的数据放到临时表中,在@s中用临时表获取数据,结果以时报告终 错误原因:执行@s语句的时候找不到执行exec(strInnerSql)产生的临时表 好郁闷啊,怎么会这样呢,明明在一个存储过程中执行的,怎么

分析存储过程重编译的起因以及避免

为了改进性能,分析重编译的起因很重要.往往,重编译可能并不需要,可以避免它以改进性能.了解导致重编译发生的不同条件有助于评估重编译的起因,并决定在重编译不必要时避免它的方法. 存储过程重编译在以下情况下发生: 存储过程语句中引用的常规表.临时表或视图的架构变化.架构变化包括表的元数据或表上索引的变化: 常规或临时表的列上的绑定(如默认/规则)变化. 表索引或列上的统计的变化超过一定的阈值. 存储过程编译时一个对象不存在,但是在执行期间创建(延迟对象解析): SET选项变化: 执行计划老化并释放:

SQL Server中临时表与表变量的区别

2009年02月20日 星期五  19:31 我 们在数据库中使用表的时候,经常会遇到两种使用表的方法,分别就是使用临时表及表变量.在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们 实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQL Ser

SQLServer中临时表与表变量的区别分析

在实际使用的时候,我们如何灵活的在存储过程中运用它们,虽然它们实现的功能基本上是一样的,可如何在一个存储过程中有时候去使用临时表而不使用表变量,有时候去使用表变量而不使用临时表呢? 临时表 临时表与永久表相似,只是它的创建是在Tempdb中,它只有在一个数据库连接结束后或者由SQL命令DROP掉,才会消失,否则就会一直存在.临时表在创建的时候都会产生SQL Server的系统日志,虽它们在Tempdb中体现,是分配在内存中的,它们也支持物理的磁盘,但用户在指定的磁盘里看不到文件. 临时表分为本地

mysql 存储过程中使用游标中使用临时表可以替代数组效果

mysql不支持数组.但有时候需要组合几张表的数据,在存储过程中,经过比较复杂的运算获取结果直接输出给调用方,比如符合条件的几张表的某些字段的组合计算,mysql临时表可以解决这个问题.临时表:只有在当前连接情况下, TEMPORARY 表才是可见的.当连接关闭时, TEMPORARY 表被自动取消.必须拥有 create temporary table 权限,才能创建临时表.可以通过指定 engine = memory; 来指定创建内存临时表. 先建立要用的数据表及数据: drop table