zoukankan      html  css  js  c++  java
  • sql server 的临时表和表变量

    临时表

    本地临时表

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

    复制代码
    -- 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)
    复制代码
    复制代码
    -- 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
    复制代码

    变量

      

    复制代码
    -- 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函数

    复制代码
    -- 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
    复制代码

    表类型

    复制代码
    -- 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

    -- 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命令

    复制代码
    -- 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

    -- 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

  • 相关阅读:
    STM32驱动WS2811
    Arduino编程器 USBasp USBtinyISP FT232-ISP 对比 区别
    USBasp制作资料及全过程(菜鸟版)
    用74HC165读8个按键状态
    C++ 使用TinyXML解析XML文件
    SD卡中FAT32文件格式快速入门(图文详细介绍)
    一个UUID生成算法的C语言实现——WIN32版本
    关于STM8S使用硬件SPI收发问题
    设计模式介绍、分类、原则
    构建完整的知识体系
  • 原文地址:https://www.cnblogs.com/baili-luoyun/p/11132267.html
Copyright © 2011-2022 走看看