存儲過程(特定功能的 SQL 語句集)一組為了完成特定功能的 SQL 語句集,存儲在數(shù)據(jù)庫中,經(jīng)過第一次編譯后再次調用不需要再次編譯,用戶通過指定存儲過程的名字并給出參數(shù)(如果該存儲過程帶有參數(shù))來執(zhí)行它。存儲過程是數(shù)據(jù)庫中的一個重要對象。 一.什么是存儲過程存儲過程,百度百科上是這樣解釋的,存儲過程(Stored Procedure)是在大型數(shù)據(jù)庫系統(tǒng)中,一組為了完成特定功能的SQL 語句集,存儲在數(shù)據(jù)庫中,經(jīng)過第一次編譯后再次調用不需要再次編譯,用戶通過指定存儲過程的名字并給出參數(shù)(如果該存儲過程帶有參數(shù))來調用存儲過程。 簡單的說就是專門干一件事一段sql語句。 可以由數(shù)據(jù)庫自己去調用,也可以由java程序去調用。 在oracle數(shù)據(jù)庫中存儲過程是procedure。 二.為什么要寫存儲過程1.效率高 存儲過程編譯一次后,就會存到數(shù)據(jù)庫,每次調用時都直接執(zhí)行。而普通的sql語句我們要保存到其他地方(例如:記事本 上),都要先分析編譯才會執(zhí)行。所以想對而言存儲過程效率更高。 2.降低網(wǎng)絡流量 存儲過程編譯好會放在數(shù)據(jù)庫,我們在遠程調用時,不會傳輸大量的字符串類型的sql語句。 3.復用性高 存儲過程往往是針對一個特定的功能編寫的,當再需要完成這個特定的功能時,可以再次調用該存儲過程。 4.可維護性高 當功能要求發(fā)生小的變化時,修改之前的存儲過程比較容易,花費精力少。 5.安全性高 完成某個特定功能的存儲過程一般只有特定的用戶可以使用,具有使用身份限制,更安全。 三.存儲過程基礎1.存儲過程結構 (1).基本結構 Oracle存儲過程包含三部分:過程聲明,執(zhí)行過程部分,存儲過程異常(可寫可不寫,要增強腳本的容錯性和調試的方便性那就寫上異常處理) (2).無參存儲過程 這里的as和is一樣任選一個,在這里沒有區(qū)別,其中demo是存儲過程名稱。 (3).有參存儲過程 a.帶參數(shù)的存儲過程 上面腳本中, 第1行:param1 是參數(shù),類型和student表id字段的類型一樣。 第3行:聲明變量name,類型是student表name字段的類型(同上)。 第4行:聲明變量age,類型數(shù)數(shù)字,初始化為20 b.帶參數(shù)的存儲過程并且進行賦值 上面腳本中: 其中參數(shù)IN表示輸入?yún)?shù),是參數(shù)的默認模式。 OUT表示返回值參數(shù),類型可以使用任意Oracle中的合法類型。 OUT模式定義的參數(shù)只能在過程體內部賦值,表示該參數(shù)可以將某個值傳遞回調用他的過程 IN OUT表示該參數(shù)可以向該過程中傳遞值,也可以將某個值傳出去 第7行:查詢語句,把參數(shù)s_age作為過濾條件,INTO關鍵字,把查到的結果賦給total變量。 第8行:輸出查詢結果,在數(shù)據(jù)庫中“||”用來連接字符串 第9—11行:做異常處理———————————————— 2.存儲過程語法 (1).運算符 這里s,m,n是變量,類型是number; (2).SELECT INTO STATEMENT語句 該語句將select到的結果賦值給一個或多個變量,例如: 上面腳本中: 存儲過程名稱:DEMO_CDD1, student是學生表,要求查出成績?yōu)?00分的那個學生的姓名,年齡,籍貫 (3).游標 Oracle會創(chuàng)建一個存儲區(qū)域,被稱為上下文區(qū)域,用于處理SQL語句,其中包含需要處理的語句,例如所有的信息,行數(shù)處理,等等。 游標是指向這一上下文的區(qū)域。 PL/SQL通過控制光標在上下文區(qū)域。游標持有的行(一個或多個)由SQL語句返回。行集合光標保持的被稱為活動集合。 a.下表是常用的游標屬性: b.使用游標 聲明游標定義游標的名稱和相關的SELECT語句: CURSOR cur_cdd IS SELECT s_id, s_name FROM student; 打開游標游標分配內存,使得它準備取的SQL語句轉換成它返回的行: OPEN cur_cdd; 抓取游標中的數(shù)據(jù),可用LIMIT關鍵字來限制條數(shù),如果沒有默認每次抓取一條: FETCH cur_cdd INTO id, name ; 關閉游標來釋放分配的內存: CLOSE cur_cdd; 四.存儲過程進階在上面的案例中,我們的存儲過程處理完所有數(shù)據(jù)要多長時間呢?事實我沒有等到它執(zhí)行完,在我可接受的時間范圍內它沒有完成。那么對于處理這種千萬級數(shù)據(jù)量的情況,存儲過程是不是束手無策呢?答案是否定的,接下來我們看看其他絕招。 我們先來分析下執(zhí)行過程的執(zhí)行過程:一個存儲過程編譯后,在一條語句一條語句的執(zhí)行時,如果遇到pl/sql語句就拿去給pl/sql引擎執(zhí)行,如果遇到sql語句就送到sql引擎執(zhí)行,然后把執(zhí)行結果再返回給pl/sql引擎。遇到一個大數(shù)據(jù)量的更新,則執(zhí)行焦點(正在執(zhí)行的,狀態(tài)處于ACTIVE)會不斷的來回切換。 Pl/SQL與SQL引擎之間的通信則稱之為上下文切換,過多的上下文切換將帶來過量的性能負載。最終導致效率降低,處理速度緩慢。 從Oracle8i開始PL/SQL引入了兩個新的數(shù)據(jù)操縱語句:FORALL、BUIK COLLECT,這些語句大大滴減少了上下文切換次數(shù)(一次切換多次執(zhí)行),同時提高DML性能,因此運用了這些語句的存儲過程在處理大量數(shù)據(jù)時速度簡直和飛一樣。 1.BUIK COLLECT Oracle8i中首次引入了Bulk Collect特性,Bulk Collect會能進行批量檢索,會將檢索結果結果一次性綁定到一個集合變量中,而不是通過游標cursor一條一條的檢索處理??梢栽赟ELECT INTO、FETCH INTO、RETURNING INTO語句中使用BULK COLLECT,接下來我們一起看看這些語句中是如何使用BULK COLLECT的。 (2).FETCH INTO 從一個集合中抓取一部分數(shù)據(jù)賦值給一個集合變量。 (3).RETURNING BULK COLLECT除了與SELECT,F(xiàn)ETCH進行批量綁定之外,還可以與INSERT,DELETE,UPDATE語句結合使用,可以返回這些DML語句執(zhí)行后所影響的記錄內容(某些字段)。 (4).注意事項 a.不能對使用字符串類型作鍵的關聯(lián)數(shù)組使用BULK COLLECT 子句。 b.只能在服務器端的程序中使用BULK COLLECT,如果在客戶端使用,就會產生一個不支持這個特性的錯誤。 c.BULK COLLECT INTO 的目標對象必須是集合類型。 d.復合目標(如對象類型)不能在RETURNING INTO 子句中使用。 e.如果有多個隱式的數(shù)據(jù)類型轉換的情況存在,多重復合目標就不能在BULK COLLECT INTO 子句中使用。 f.如果有一個隱式的數(shù)據(jù)類型轉換,復合目標的集合(如對象類型集合)就不能用于BULK COLLECTINTO 子句中。 五.存儲過程優(yōu)化思路:
|
|