臨時表
本地臨時表
適合開銷昂貴 結果集是個非常小的集合
-- 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

