存儲過程-使用游標、臨時表、表變量、實現對表中數據進行操作


工作中經常會遇到批量處理一些數據,一般的方法可以使用代碼開發相應的功能,在前端操作相應的功能,但是如果操作的數據不是特別的復雜,但是數據量特別的大,在客戶端操作就會由於操作時間等待過長而導致客戶體驗度降低,這時我們就要考慮采用數據庫中的存儲過程進行操作,存儲過程的優點我再這里就不再多介紹,詳細的請參考的我的另一篇有關存儲過程的介紹:https://www.cnblogs.com/mingqi-420/p/10664908.html。下面分別介紹游標和臨時表兩種方法對數據庫中的表進行循環操作:

1、游標:

分類:

MS SQL SERVER 支持三種類型的游標:Transact_SQL 游標,API 服務器游標和客戶游標。

(1) Transact_SQL 游標

Transact_SQL 游標是由DECLARE CURSOR 語法定義、主要用在Transact_SQL 腳本、存儲過程和觸發器中。Transact_SQL 游標主要用在服務器上,由從客戶端發送給服務器的Transact_SQL 語句或是批處理、存儲過程、觸發器中的Transact_SQL 進行管理。Transact_SQL 游標不支持提取塊或多行。

(2) API 游標

API 游標支持在OLE DB, ODBC 以及DB_library 中使用游標函數,主要用在服務器上。每一次客戶端應用程序調用API 游標函數,MS SQL SEVER 的OLE DB 提供者、ODBC驅動器或DB_library 的動態鏈接庫(DLL) 都會將這些客戶請求傳送給服務器以對API游標進行處理。

(3) 客戶游標

客戶游標主要是當在客戶機上緩存結果集時才使用。在客戶游標中,有一個缺省的結果集被用來在客戶機上緩存整個結果集。客戶游標僅支持靜態游標而非動態游標。由於服務器游標並不支持所有的Transact-SQL 語句或批處理,所以客戶游標常常僅被用作服務器游標的輔助。因為在一般情況下,服務器游標能支持絕大多數的游標操作。

由於API 游標和Transact-SQL 游標使用在服務器端,所以被稱為服務器游標,也被稱為后台游標,而客戶端游標被稱為前台游標。

優點:

1)允許程序對由查詢語句select返回的行集合中的每一行執行相同或不同的操作,而不是對整個行集合執行同一個操作。

2)提供對基於游標位置的表中的行進行刪除和更新的能力。

3)游標實際上作為面向集合的數據庫管理系統(RDBMS)和面向行的程序設計之間的橋梁,使這兩種處理方式通過游標溝通起來。

缺點:

處理大數據量時,效率低下,占用內存大;
一般來說,能使用其他方式處理數據時,最好不要使用游標,除非是當你使用while循環,子查詢,臨時表,表變量,自建函數或其他方式都無法處理某種操作的時候,再考慮使用游標。

CREATE PROCEDURE pro_mycursor
AS
--聲明1個變量
declare @name nvarchar(20)  
/*聲明一個游標mycursor,select語句中參數的個數必須要和從游標取出的變量名相同*/
declare mycursor cursor for select name from student
--打開游標
open mycursor
--從游標里取出數據賦值到我們剛才聲明的2個變量中
fetch next from mycursor into @name
 --判斷游標的狀態
--0 fetch語句成功    
-- -1 fetch語句失敗或此行不在結果集中    
-- -2被提取的行不存在
while (@@fetch_status=0)
begin
--顯示出我們每次用游標取出的值 或者進行一些其他的一些操作
   print '游標成功取出一條數據'
   print @name
--用游標去取下一條記錄
   fetch next from mycursor into @name
end
--關閉游標
close mycursor
--撤銷游標
deallocate mycursor

GO

2、臨時表

 1 CREATE PROCEDURE pro_temptable
 2 AS
 3     BEGIN
 4 --臨時表
 5         CREATE TABLE #t ( name NVARCHAR(50) );
 6         INSERT  INTO #t
 7                 ( name )
 8                 SELECT  name
 9                 FROM    student;
10  --select * from #t
11  --drop table #t
12         DECLARE @name INT;
13         WHILE EXISTS ( SELECT   [name]
14                        FROM     #t )
15             BEGIN  
16                 SELECT TOP 1
17                         @name = [name]
18                 FROM    #t; 
19               --打印名稱  或者做其他的操作
20                 PRINT @name;          
21                --刪除臨時表    
22                 DELETE  FROM #t
23                 WHERE   name = @name;   
24         --SELECT  * FROM    #t
25          --EXEC('drop table '+)
26             --PRINT  @name  
27             END;
28     END;

 

3、表變量:

CREATE PROC pro_table
AS
BEGIN
DECLARE @tb1 Table
  (
   Name varchar(20)
  )
  INSERT INTO @tb1 SELECT name FROM student
    DECLARE @name INT;
        WHILE EXISTS ( SELECT   name
                       FROM     @tb1 )
            BEGIN  
                SELECT TOP 1
                         @name = name
                FROM    student; 
             --打印名稱  或者做其他的操作
                PRINT @name;          
             END
 END

4、臨時表和表變量的比較

(1)臨時表是利用了硬盤(tempdb數據庫) ,表名變量是占用內存,因此小數據量當然是內存中的表變量更快。當大數據量時,就不能用表變量了,太耗內存了。大數據量時適合用臨時表。
(2)表變量缺省放在內存,速度快,所以在觸發器,存儲過程里如果數據量不大,應該用表變量。
臨時表缺省使用硬盤,一般來說速度比較慢,那是不是就不用臨時表呢?也不是,在數據量比較大的時候,如果使用表變量,會把內存耗盡,然后使用 TEMPDB的空間,這樣主要還是使用硬盤空間,但同時把內存基本耗盡,增加了內存調入調出的機會,反而降低速度。這種情況建議先給TEMPDB一次分配合適的空間,然后使用臨時表。
(3)臨時表相對而言表變量主要是多了I/O時間,但少了對內存資源的占用。數據量較大的時候,由於對內存資源的消耗較少,使用臨時表比表變量有更好的性能。
(4)建議:觸發器、自定義函數用表變量;存儲過程看情況,大部分用表變量;特殊的應用,大數據量的場合用臨時表。
(5)表變量有明確的作用域,在定義表變量的函數、存儲過程或批處理結束時,會自動清除表變量。
(6)在存儲過程中使用表變量與使用臨時表相比,減少了存儲過程的重新編譯量。
(7)涉及表變量的事務只在表變量更新期間存在。這樣就減少了表變量對鎖定和記錄資源的需求。
(8)表變量需要事先知道表結構,普通臨時表,只在當前會話中可用與表變量相同into一下就可以了,方便;全局臨時表:可在多個會話中使用存在於temp中需顯示的drop。(不知道表結構情況下臨時表方便一些)
(9)全局臨時表的功能是表變量沒法達到的。
(10)表變量不必刪除,也就不會有命名沖突,臨時表特別是全局臨時表用的時候必須解決命名沖突。
(11)應避免頻繁創建和刪除臨時表,減少系統表資源的消耗。
(12)在新建臨時表時,如果一次性插入數據量很大,那么可以使用select into代替create table,避免log,提高速度;如果數據量不大,為了緩和系統表的資源,建議先create table,然后insert。
(13)如果臨時表的數據量較大,需要建立索引,那么應該將創建臨時表和建立索引的過程放在單獨一個子存儲過程中,這樣才能保證系統能夠很好的使用到該臨時表的索引。
(14)如果使用到了臨時表,在存儲過程的最后務必將所有的臨時表顯式刪除,先truncate table,然后drop table,這樣可以避免系統表的較長時間鎖定。
(15)慎用大的臨時表與其他大表的連接查詢和修改,減低系統表負擔,因為這種操作會在一條語句中多次使用tempdb的系統表。

大家可根據實際情況和這三者的優缺點合理的選擇,如果有什么問題或者還有更好的方式,歡迎大家積極指正!!!


免責聲明!

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



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