mysql臨時表

臨時表與永久表相似,但臨時表存儲在tempdb中,當不再使用時會自動刪除。

什麼時候使用臨時表?
在SQL Server的性能調優中,如何在一段需要長時間的代碼或被頻繁調用的代碼中處理臨時數據集,表變量和臨時表是兩種選擇。

臨時表是有它的作用的,但不能濫用,當一個查詢涉及很多表時,查詢的笛卡爾積是非常大的,單純的用索引可能解決不了查詢時間的問題.這個時候可以用臨時表,將一個查詢分成多步完成,減少輸出查詢結果時的笛卡爾積,會對提高查詢效率有很大的幫助.比如
查詢的主表有上百W條數據,條件都是針對主表字段,然後1:M:M關聯兩個子表,如果直接關聯查詢,那麼笛卡爾積可能爲100W*M*100W*n*100W,可能就會造成耗時很長或查詢超時.用臨時表先篩選出主表的數據,比如篩選取主表後還有1000條數據滿足條件要求,這時再用臨時表來關聯兩個子表,笛卡爾積就會下降一個幾何積,會明顯提高查詢速度.
什麼時候用臨時表,取決於查詢的複雜成度和數據量,簡單的查詢用臨時表就得不償失了.

如利用臨時表來組織數據,比普通表會更加的簡潔、緊湊。這主要是在臨時表中可以實現很多的特性。如可以進行預處理計算。如當發現基本標中的索引不怎麼合適,也可以在數據庫臨時表中重新創建索引以優化原有的索引。特別是當需要多次訪問某個表或者視圖的時候,利用臨時表來組織數據是一個提高效率的好方法。即使只是一個簡單的查詢,其效率的提升也是很明顯的。爲此,使用臨時表最明顯的一個好處就似乎可以提高數據庫的性能,特別是查詢的性能。

  另外使用臨時表還可以減少中間表的產生。在進行某些操作時,本來往往需要一些中間表的幫助纔可以完成。而現在數據庫管理員可以讓數據庫在需要時自動生成中間表,並在用完後進行自動刪除。如此的話,中間表的建立與刪除就不需要數據庫管理員人爲的管理了。所以,使用臨時表可以減少數據庫系統中的垃圾表,也可以降低用戶的工作量。

\\\\\\\\\\\\\\\\\\\\\\\\\\\
臨時表和表變量的作用域範圍:

   表變量的作用域範圍是所在的批處理,而臨時表的作用域範圍是整個會話。還有表變量不會產生統計信息,這有兩個主要後果:第一是查詢優化器對錶變量行數的估計爲固定值而不管表變量中的數據是什麼,第二添加或刪除數據並不會改變估計的值。

不能爲表變量創建索引但是可以爲臨時表創建索引。

臨時表:
臨時對象都以#或##爲前綴,臨時表是臨時對象的一種。還有例如臨時存儲過程、臨時函數之類的臨時對象,臨時對象都存儲在tempdb中。
以#前綴的臨時表爲本地的,因此只有在當前用戶會話中纔可以訪問,而##前綴的臨時表是全局的,因此所有用戶會話都可以訪問。
臨時表以會話爲邊界,只要創建臨時表的會話沒有結束臨時表就會持續存在。當然用戶在會話中可以通過DROP TABLE命令提前銷燬臨時表。

除非使用 DROP TABLE 語句顯式除去臨時表,否則臨時表將在退出其作用域時由系統自動除去:所有其它本地臨時表在當前會話結束時自動除去。

當存儲過程完成時,將自動除去在存儲過程中創建的本地臨時表。由創建表的存儲過程執行的所有嵌套存儲過程都可以引用此表。但調用創建此表的存儲過程的進程無法引用此表。

全局臨時表在創建此表的會話結束且其它任務停止對其引用時自動除去。任務與表之間的關聯只在單個 Transact-SQL 語句的生存週期內保持。換言之,當創建全局臨時表的會話結束時,最後一條引用此表的 Transact-SQL 語句完成後,將自動除去此表。

當創建本地或全局臨時表時,CREATE TABLE 語法支持除 FOREIGN KEY 約束以外的其它所有約束定義。如果在臨時表中指定 FOREIGN KEY 約束,該語句將返回警告信息,指出此約束已被忽略,表仍會創建,但不具有 FOREIGN KEY 約束。在 FOREIGN KEY 約束中不能引用臨時表。

考慮使用表變量而不使用臨時表。當需要在臨時表上顯式地創建索引時,或多個存儲過程或函數需要使用表值時,臨時表很有用。通常,表變量提供更有效的查詢處理。

SQL Server創建和使用臨時表:
創建臨時表
方法一:
create table #臨時表名(字段1 約束條件,
字段2 約束條件,
…..)
create table ##臨時表名(字段1 約束條件,
字段2 約束條件,
…..)

方法二:
    select * into #臨時表名 from 你的表;
    select * into ##臨時表名 from 你的表;

注:以上的#代表局部臨時表,##代表全局臨時表

查詢臨時表
select * from #臨時表名;
select * from ##臨時表名;

刪除臨時表
drop table #臨時表名;
drop table ##臨時表名;

\\\\\\\\\\\\\\\\\\\\\\\\\\\
臨時表的存儲:

我們前面說過臨時表存儲在tempdb中因此臨時表的訪問是有可能造成物理IO的,當然在修改時也需要生成日誌來確保一致性,同時鎖機制也是不可缺少的。
跟表變量另外一個顯著區別就是,臨時表可以創建索引也可以定義統計數據,因此SQL Server在處理訪問臨時表的語句時需要考慮執行計劃優化的問題。簡單地總結我們對於較小的臨時計算用數據集推薦使用表變量。如果數據集比較大如果在代碼中用於臨時計算同時這種臨時使用永遠都是簡單的全數據集掃描而不需要考慮什麼優化,比如說沒有分組或分組很少的聚合(比如說COUNT、SUM、AVERAGE、MAX等)也可以考慮使用表變量。使用表變量另外一個考慮因素是應用環境的內存壓力,如果代碼的運行實例很多就要特別注意內存變量對內存的消耗。一般對於大的數據集推薦使用臨時表同時創建索引或者通過SQL Server的統計數據(Statisitcs)自動創建和維護功能來提供訪問SQL語句的優化。如果需要在多個用戶會話間交換數據當然臨時表就是唯一的選擇了。需要提及的是由於臨時表存放在tempdb中因此要注意tempdb的調優。

臨時表存儲在TempDB數據庫中,所有的使用此SQL Server 實例的用戶都共享這個TempDB,因爲我們應該確保用來存儲TempDB數據庫的硬盤有足夠的空間,以使之能夠自己的增長.最好能夠存儲在一個擁有獨立硬盤控制器上.因爲這樣不存在和其它的硬盤I/O進行爭用.
臨時表主要會增加tempdb的IO,導致性能下降。

tempdb
tempdb全局存儲內部對象,用戶對象,臨時表,臨時對象,以及SQL Server操作創建的存儲過程。每個數據庫實例只有一個tempdb,所以可能存在性能以及磁盤空間瓶頸。各種形式的可用空間及過度的DDL/DML操作都會導致tempdb負載過重。這會導致運行在服務器上不相干程序運行緩慢或者運行失敗。

  tempdb的一些常見通病如下:

  –耗完了tempdb的所有存儲空間
  –讀取tempdb時的I/O瓶頸造成的查詢運行緩慢。
  –過度的DDL操作造成在系統表上的瓶頸。

總的tempdb空間=用戶對象+內部對象+存儲的版本信息+空閒空間。
這個空閒空間大小跟tempdb性能計數器上空閒空間是一樣的。

\\\\\\\\\\\\\\\\\\\\\\\\\\\
局部臨時表:

如果本地臨時表由存儲過程創建或由多個用戶同時執行的應用程序創建,則 SQL Server 必須能夠區分由不同用戶創建的表。爲此,SQL Server 在內部爲每個本地臨時表的表名追加一個數字後綴。存儲在 tempdb 數據庫的 sysobjects 表中的臨時表,
其全名由 CREATE TABLE 語句中指定的表名和系統生成的數字後綴組成。爲了允許追加後綴,爲本地臨時表指定的表名 table_name 不能超過 116 個字符。

局部臨時表不能夠被其它連接所共享的原因就是因爲局部臨時表的表名後面加上了一個唯一字符來標識.如:

create table #DimCustomer_test
(
ID int IDENTITY (1,1) not null,
WokNo varchar(50),
primary key (ID)
);

現在我們來查看一下TempDB中 sysobjects表,我們會發現我們新創建的臨時表#DimCustomer_test已經被加上了後綴:
USE TempDB
GO
SELECT name FROM sysobjects WHERE name LIKE ’%DimCustomer%’
the Result is:

DimCustomer_test________________________________000000000005

全局臨時表
create table ##DimCustomer_test
(
ID int IDENTITY (1,1) not null,
WokNo varchar(50),
primary key (ID)
);
現在我們來查看一下TempDB中 sysobjects表,我們會發現我們新創建的臨時表##DimCustomer_test沒有被加上了後綴:
USE TempDB
GO
SELECT name FROM sysobjects WHERE name LIKE ’%DimCustomer%’
The Result are:

DimCustomer_test

可以看到我們剛纔創建的全局臨時表名字並沒有被加上標識.

\\\\\\\\\\\\\\\\\\\\\\\\\\\
相關例子:
Sql代碼 收藏代碼

drop table #Tmp   --刪除臨時表#Tmp  
create table #Tmp --創建臨時表#Tmp  
(  
    ID   int IDENTITY (1,1)     not null, --創建列ID,並且每次新增一條記錄就會加1  
    WokNo                varchar(50),    
    primary key (ID)      --定義ID爲臨時表#Tmp的主鍵       
);  
Select * from #Tmp    --查詢臨時表的數據  
truncate table #Tmp --清空臨時表的所有數據和約束  


Declare @Wokno Varchar(500) --用來記錄職工號  
Declare @Str NVarchar(4000) --用來存放查詢語句  
Declare @Count int --求出總記錄數       
Declare @i int  
Set @i = 0  
Select @Count = Count(Distinct(Wokno)) from #Tmp  
While @i < @Count  
    Begin  
       Set @Str = 'Select top 1 @Wokno = WokNo from #Tmp Where id not in (Select top ' + Str(@i) + 'id from #Tmp)'  
       Exec Sp_ExecuteSql @Str,N'@WokNo Varchar(500) OutPut',@WokNo Output  
       Select @WokNo,@i --一行一行把職工號顯示出來  
       Set @i = @i + 1  
    End  

\\\\\\\\\\\\\\\\\\\\\\\\\\\
引用臨時表的PRO的編譯:

例子
Sql代碼 收藏代碼

--SP1  
create procedure Proc1  
as   
begin  
   create table #t1(a int, b int);   
   insert into #t1 values(1,2);  
   select * from #t1;  
end  

exec Proc1  
go   
exec Proc1  
GO  

Sql代碼 收藏代碼

--SP2  
create procedure Proc1  
as   
begin  
   create table #t1(a int, b int);   
   insert into #t1 values(1,2);  
   exec Proc2;   
end  
go  

create procedure Proc2  
as  
begin  
      select * from #t1;  
end  
go  


exec Proc1  
go  
exec Proc1  
go  

我們可以看到,上面的2個例子,SP1跟SP2,
在SP1中第二次執行exec Proc1的時候,不會引起重編譯,
但是在SP2中第二次執行exec Proc1的時候,卻會引起重編譯,爲什麼呢?

參考答案:

1.第一個case,我很久以前經常用表變量去inner join其它的表,當發現表變量數據稍多,整個語句就會變的很差,之後就一直按“數據很少就用表變量,數據多點就用臨時表。”剛看到這個貼子,就想了想查了查,主要原因還是表變量的行數未知,SQL優化器必須估一個值,這個值往往是很小,在這種情況下去inner join其它表,基本上都會是Nested loop join,此時一旦表變量數據量大,性能將會變得極差。而這種情況下我們往往需要merge join 或 hash join才更有效率,recompile選項能讓優化器去更新表變量的統計信息,而這樣就能根據統計信息生成合理的執行計劃。

2.至於第二個關於存儲過程的case,兩個場景主要關鍵點還是第二個proc2中引用非自己創建的臨時表,這個引用是依靠臨時表ID,當執行proc1生成臨時表時,名字(執行計劃依靠名字)不變但id會變,而proc2依靠這個id,這相當於proc2要查的臨時表架構發生變化,所以每次都要重編譯,如果在proc1裏同時有兩個exec proc2,那麼第二個不會重編譯,因爲此時它可以重新第一個exec proc2的執行計劃了,因爲兩個exec proc2引用的臨時表是同名同ID。

相關文檔參考:
http://www.mssqltips.com/sqlservertip/2140/improving-sql-server-performance-when-using-table-variables/
http://blogs.msdn.com/b/psssql/archive/2010/08/24/query-performance-and-table-variables.aspx
http://blogs.msdn.com/b/sqlprogrammability/archive/2007/01/18/11-0-temporary-tables-table-variables-and-recompiles.aspx

這是我做過的臨時表(僅供圖片參考):

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章