工做中常常會遇到批量處理一些數據,通常的方法可使用代碼開發相應的功能,在前端操做相應的功能,可是若是操做的數據不是特別的複雜,可是數據量特別的大,在客戶端操做就會因爲操做時間等待過長而致使客戶體驗度下降,這時咱們就要考慮採用數據庫中的存儲過程進行操做,存儲過程的優勢我再這裏就再也不多介紹,詳細的請參考的個人另外一篇有關存儲過程的介紹:https://www.cnblogs.com/mingqi-420/p/10664908.html。下面分別介紹遊標和臨時表兩種方法對數據庫中的表進行循環操做:html
一、遊標:前端
分類:數據庫
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遊標進行處理。fetch
(3) 客戶遊標大數據
客戶遊標主要是當在客戶機上緩存結果集時才使用。在客戶遊標中,有一個缺省的結果集被用來在客戶機上緩存整個結果集。客戶遊標僅支持靜態遊標而非動態遊標。因爲服務器遊標並不支持全部的Transact-SQL 語句或批處理,因此客戶遊標經常僅被用做服務器遊標的輔助。由於在通常狀況下,服務器遊標能支持絕大多數的遊標操做。spa
因爲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
二、臨時表
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;
三、表變量:
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
四、臨時表和表變量的比較
(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的系統表。
你們可根據實際狀況和這三者的優缺點合理的選擇,若是有什麼問題或者還有更好的方式,歡迎你們積極指正!!!