sql server 的临时表和表变量

摘要:
表变量是一种变量。表变量也分为局部变量和全局变量。本地表变量的名称前缀为“@”,只能在本地当前用户连接中访问。全局表变量的名称前缀为“@@”。它们通常是系统的全局变量。正如我们经常使用的,@@Error表示错误数,@@RowCount表示受影响的行数。

临时表

本地临时表

  适合开销昂贵   结果集是个非常小的集合

sql server 的临时表和表变量第1张
复制代码
-- Local Temporary Tables

IF OBJECT_ID('tempdb.dbo.#MyOrderTotalsByYear') IS NOT NULL
  DROP TABLE dbo.#MyOrderTotalsByYear;
GO

CREATE TABLE #MyOrderTotalsByYear
(
  orderyear INT NOT NULL PRIMARY KEY,
  qty       INT NOT NULL
);

INSERT INTO #MyOrderTotalsByYear(orderyear, qty)
  SELECT
    YEAR(O.orderdate) AS orderyear,
    SUM(OD.qty) AS qty
  FROM Sales.Orders AS O
    JOIN Sales.OrderDetails AS OD
      ON OD.orderid = O.orderid
  GROUP BY YEAR(orderdate);

SELECT Cur.orderyear, Cur.qty AS curyearqty, Prv.qty AS prvyearqty
FROM dbo.#MyOrderTotalsByYear AS Cur
  LEFT OUTER JOIN dbo.#MyOrderTotalsByYear AS Prv
    ON Cur.orderyear = Prv.orderyear + 1;
GO
复制代码

全局临时表

复制代码
CREATE TABLE ##Temp
(
    id int,
    customer_name nvarchar(50),
    age int
)

INSERT INTO ##Temp VALUES(1,'老王',20),(2,'老张',30),(3,'老李',25)
复制代码
sql server 的临时表和表变量第1张
复制代码
-- Global Temporary Tables
CREATE TABLE dbo.##Globals
(
  id  sysname     NOT NULL PRIMARY KEY,
  val SQL_VARIANT NOT NULL
);

-- Run from any session
INSERT INTO dbo.##Globals(id, val) VALUES(N'i', CAST(10 AS INT));

-- Run from any session
SELECT val FROM dbo.##Globals WHERE id = N'i';

-- Run from any session
DROP TABLE dbo.##Globals;
GO
复制代码

变量

  sql server 的临时表和表变量第9张

sql server 的临时表和表变量第10张

sql server 的临时表和表变量第1张
复制代码
-- Table Variables
DECLARE @MyOrderTotalsByYear TABLE
(
  orderyear INT NOT NULL PRIMARY KEY,
  qty       INT NOT NULL
);

INSERT INTO @MyOrderTotalsByYear(orderyear, qty)
  SELECT
    YEAR(O.orderdate) AS orderyear,
    SUM(OD.qty) AS qty
  FROM Sales.Orders AS O
    JOIN Sales.OrderDetails AS OD
      ON OD.orderid = O.orderid
  GROUP BY YEAR(orderdate);

SELECT Cur.orderyear, Cur.qty AS curyearqty, Prv.qty AS prvyearqty
FROM @MyOrderTotalsByYear AS Cur
  LEFT OUTER JOIN @MyOrderTotalsByYear AS Prv
    ON Cur.orderyear = Prv.orderyear + 1;
GO
复制代码

LAG函数

sql server 的临时表和表变量第1张
复制代码
-- with the LAG function
DECLARE @MyOrderTotalsByYear TABLE
(
  orderyear INT NOT NULL PRIMARY KEY,
  qty       INT NOT NULL
);

INSERT INTO @MyOrderTotalsByYear(orderyear, qty)
  SELECT
    YEAR(O.orderdate) AS orderyear,
    SUM(OD.qty) AS qty
  FROM Sales.Orders AS O
    JOIN Sales.OrderDetails AS OD
      ON OD.orderid = O.orderid
  GROUP BY YEAR(orderdate);

SELECT orderyear, qty AS curyearqty,
  LAG(qty) OVER(ORDER BY orderyear) AS prvyearqty
FROM @MyOrderTotalsByYear;
GO
复制代码

表类型

sql server 的临时表和表变量第1张
复制代码
-- Table Types
IF TYPE_ID('dbo.OrderTotalsByYear') IS NOT NULL
  DROP TYPE dbo.OrderTotalsByYear;

CREATE TYPE dbo.OrderTotalsByYear AS TABLE
(
  orderyear INT NOT NULL PRIMARY KEY,
  qty       INT NOT NULL
);
GO

-- Use table type
DECLARE @MyOrderTotalsByYear AS dbo.OrderTotalsByYear;

INSERT INTO @MyOrderTotalsByYear(orderyear, qty)
  SELECT
    YEAR(O.orderdate) AS orderyear,
    SUM(OD.qty) AS qty
  FROM Sales.Orders AS O
    JOIN Sales.OrderDetails AS OD
      ON OD.orderid = O.orderid
  GROUP BY YEAR(orderdate);

SELECT orderyear, qty FROM @MyOrderTotalsByYear;
GO
复制代码

动态SQL

sql server 的临时表和表变量第1张
-- Simple example of EXEC
DECLARE @sql AS VARCHAR(100);
SET @sql = 'PRINT ''This message was printed by a dynamic SQL batch.'';';
EXEC(@sql);
GO

EXEC命令

sql server 的临时表和表变量第1张
复制代码
-- Simple example using sp_executesql
DECLARE @sql AS NVARCHAR(100);

SET @sql = N'SELECT orderid, custid, empid, orderdate
FROM Sales.Orders
WHERE orderid = @orderid;';

EXEC sys.sp_executesql
  @stmt = @sql,
  @params = N'@orderid AS INT',
  @orderid = 10248;
GO
复制代码

使用动态SQL的PIVOT

sql server 的临时表和表变量第1张
-- Static PIVOT
SELECT *
FROM (SELECT shipperid, YEAR(orderdate) AS orderyear, freight
      FROM Sales.Orders) AS D
  PIVOT(SUM(freight) FOR orderyear IN([2006],[2007],[2008])) AS P;

例程

用户自定义函数

存储过程

触发器

错误处理

  表变量创建的语法类似于临时表,区别就在于创建的时候,必须要为之命名。表变量是变量的一种,表变量也分为本地及全局的两种,本地表变量的名称都是以“@”为前缀,只有在本地当前的用户连接中才可以访问。全局的表变量的名称都是以“@@”为前缀,一般都是系统的全局变量,像我们常用到的,如@@Error代表错误的号,@@RowCount代表影响的行数。

复制代码
DECLARE @News Table 
  ( 
  News_id int NOT NULL, 
  NewsTitle varchar(100), 
  NewsContent varchar(2), 
  NewsDateTime datetime 
  )
复制代码

临时表和表变量的选择

复制代码
--表变量:  
  DECLARE @tb  table(id   int   identity(1,1), name   varchar(100))   
  INSERT @tb  

  SELECT id, name 
  FROM mytable 

  WHERE name like ‘zhang%’ 

--临时表: 
  SELECT name, address
  INTO #ta   FROM mytable  
  WHERE name like ‘zhang%’
复制代码

  临时表是利用了硬盘(tempdb数据库) ,表名变量是占用内存,因此小数据量当然是内存中的表变量更快。当大数据量时,就不能用表变量了,太耗内存了。大数据量时适合用临时表。

  表变量缺省放在内存,速度快,所以在触发器,存储过程里如果数据量不大,应该用表变量。

  临时表缺省使用硬盘,一般来说速度比较慢,那是不是就不用临时表呢?也不是,在数据量比较大的时候,如果使用表变量,会把内存耗尽,然后使用 TEMPDB的空间,这样主要还是使用硬盘空间,但同时把内存基本耗尽,增加了内存调入调出的机会,反而降低速度。这种情况建议先给TEMPDB一次分配合适的空间,然后使用临时表。

  临时表相对而言表变量主要是多了I/O时间,但少了对内存资源的占用。数据量较大的时候,由于对内存资源的消耗较少,使用临时表比表变量有更好的性能。

  建议:触发器、自定义函数用表变量;存储过程看情况,大部分用表变量;特殊的应用,大数据量的场合用临时表。

  表变量有明确的作用域,在定义表变量的函数、存储过程或批处理结束时,会自动清除表变量。

  在存储过程中使用表变量与使用临时表相比,减少了存储过程的重新编译量。

  涉及表变量的事务只在表变量更新期间存在。这样就减少了表变量对锁定和记录资源的需求。

  表变量需要事先知道表结构,普通临时表,只在当前会话中可用与表变量相同into一下就可以了,方便;全局临时表:可在多个会话中使用存在于temp中需显示的drop。(不知道表结构情况下临时表方便一些)

  全局临时表的功能是表变量没法达到的。

  表变量不必删除,也就不会有命名冲突,临时表特别是全局临时表用的时候必须解决命名冲突。

  应避免频繁创建和删除临时表,减少系统表资源的消耗。

  在新建临时表时,如果一次性插入数据量很大,那么可以使用select into代替create table,避免log,提高速度;如果数据量不大,为了缓和系统表的资源,建议先create table,然后insert。

  如果临时表的数据量较大,需要建立索引,那么应该将创建临时表和建立索引的过程放在单独一个子存储过程中,这样才能保证系统能够很好的使用到该临时表的索引。

  如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncate table,然后drop table,这样可以避免系统表的较长时间锁定。

  慎用大的临时表与其他大表的连接查询和修改,减低系统表负担,因为这种操作会在一条语句中多次使用tempdb的系统表。

  使用表变量主要需要考虑的就是应用程序对内存的压力,如果代码的运行实例很多,就要特别注意内存变量对内存的消耗。

  我们对于较小的数据或者是通过计算出来的推荐使用表变量。

  如果数据的结果比较大,在代码中用于临时计算,在选取的时候没有什么分组的聚合,就可以考虑使用表变量。

  一般对于大的数据结果,或者因为统计出来的数据为了便于更好的优化,我们就推荐使用临时表,同时还可以创建索引,由于临时表是存放在Tempdb中,一般默认分配的空间很少,需要对tempdb进行调优,增大其存储的空间。

  CTE和WITH AS短语结合使用提高SQL查询性能:

  CET要比表变量效率高得多!

  表变量实际上使用了临时表,从而增加了额外的I/O开销,因此,表变量的方式并不太适合数据量大且频繁查询的情况。

 资料

https://blog.csdn.net/lishimin1012/article/details/54137787

https://www.cnblogs.com/Jessy/archive/2013/06/13/3133958.html

免责声明:文章转载自《sql server 的临时表和表变量》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇将dll文件注入到其他进程中的一种新方法洛谷训练新手村之“简单字符串”题解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

jmeter 中的 Beanshell 使用

一、操作变量:通过使内置对象vars可以对变量进行存取操作     a) vars.get("name"):从jmeter中获得变量值     b) vars.put("key","value"):数据存到jmeter变量中 二、操作属性:通过使用Bean shell内置对象props 可以对属性进行存取操作     a) props.get("STAR...

如何用java实现两个变量值的互换!

1、通过第三方变量实现两个变量的交换:          2、通过已有的两个变量之间的加或减实现:          这种方法对于两个都是无限接进int取值范围,而相加超出int取值范围的情况不适用。 3. 指针地址操作因为对地址的操作实际上进行的是整数运算,比如:两个地址相减得到一个整数,表示两个变量在内存中的储存位置隔了多少个字节;地址和一个整数相加即...

SPSS基础知识

3.1 数据的输入和保存 1. 打开SPSS后,界面包括变量视图和数据视图。 变量视图,用于对变量进行设置,数据视图为用户输入的数据。 2. SPSS有大量的函数调用功能进行数据分析 常用的数据分析包括比较均值、一般线性模型、广义线性模型、回归分析、相关分析、神经网络、分类和降维(适用于经济学、评价因子值和得分计算等问题)等等。 3.2 SPSS图形绘制...

mysql如何修改所有的definer

mysql中的definer是什么,有什么作用? 我们在mysql创建view、trigger、function、procedure、event时都会定义一个Definer=‘xxx’,类似如下: CREATE ALGORITHM =UNDEFINED DEFINER = `root`@`%` SQL SECURITY DEFI...

gdb查看内存(转)

可以使用examine命令(简写是x)来查看内存地址中的值。x命令的语 法如下所示:x/<n/f/u> <addr>n、f、u是可选的参数。 n是一个正整数,表示需要显示的内存单元的个数,也就是说从当前地址向后显示几个 内存单元的内容,一个内存单元的大小由后面的u定义。 f 表示显示的格式,参见下面。如果地址所指的是字符串,那么格式...

【转】JMeter学习(三十二)属性和变量

一、Jmeter中的属性: 1、JMeter属性统一定义在jmeter.properties文件中,我们可以在该文件中添加自定义的属性 2、JMeter属性在测试脚本的任何地方都是可见的(全局),通常被用来定义一些JMeter使用的默认值,可以用于在线程间传递信息。 3、JMeter属性可以在测试计划中通过函数 _P 进行引用,但是不能作为特定线程的变量值...