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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM