在b/s系統(tǒng)的構(gòu)建過程中茂嗓,數(shù)據(jù)庫操作幾乎成為了一個(gè)必不可少的操作赁还。調(diào)用存儲過程實(shí)現(xiàn)數(shù)據(jù)庫操作使很多程序員使用的方法独悴,而且大多數(shù)的程序員都是能使用存儲過程就使用存儲過程耸袜,很少直接使用sql語句扇谣,所以存儲過程是很有用而且很重要的昧捷。
存儲過程簡介
存儲過程的定義:完成一定功能的可重復(fù)調(diào)用的程序
簡單的說,存儲過程是由一些sql語句和控制語句組成的被封裝起來的過程罐寨,它駐留在數(shù)據(jù)庫中靡挥,可以被客戶應(yīng)用程序調(diào)用,也可以從另一個(gè)過程或觸發(fā)器調(diào)用鸯绿。它的參數(shù)可以被傳遞和返回跋破。與應(yīng)用程序中的函數(shù)過程類似,存儲過程可以通過名字來調(diào)用瓶蝴,而且它們同樣有輸入?yún)?shù)和輸出參數(shù)幔烛。
根據(jù)返回值類型的不同,我們可以將存儲過程分為三類:返回記錄集的存儲過程囊蓝,返回?cái)?shù)值的存儲過程(也可以稱為標(biāo)量存儲過程)饿悬,以及行為存儲過程。顧名思義聚霜,返回記錄集的存儲過程的執(zhí)行結(jié)果是一個(gè)記錄集狡恬,典型的例子是從數(shù)據(jù)庫中檢索出符合某一個(gè)或幾個(gè)條件的記錄珠叔;返回?cái)?shù)值的存儲過程執(zhí)行完以后返回一個(gè)值,例如在數(shù)據(jù)庫中執(zhí)行一個(gè)有返回值的函數(shù)或命令弟劲;最后祷安,行為存儲過程僅僅是用來實(shí)現(xiàn)數(shù)據(jù)庫的某個(gè)功能,而沒有返回值兔乞,例如在數(shù)據(jù)庫中的更新和刪除操作汇鞭。
存儲過程的通俗解釋:你使用手機(jī)撥打A同事的手機(jī),需要一個(gè)一個(gè)號碼的輸入庸追,然后才能撥打
而如果你把這個(gè)號碼設(shè)置為快速撥號霍骄,那么你只要長按1(自己設(shè)置的數(shù)字鍵)就可以直接撥打電話了
把這個(gè)號碼設(shè)置為快速撥號的過程你就可以理解為創(chuàng)建存儲過程。
使用存儲過程的好處
相對于直接使用sql語句淡溯,在應(yīng)用程序中直接調(diào)用存儲過程有以下好處:
(1)減少網(wǎng)絡(luò)通信量读整。調(diào)用一個(gè)行數(shù)不多的存儲過程與直接調(diào)用sql語句的網(wǎng)絡(luò)通信量可能不會有很大的差別,可是如果存儲過程包含上百行sql語句咱娶,那么其性能絕對比一條一條的調(diào)用sql語句要高得多米间。
(2)執(zhí)行速度更快。有兩個(gè)原因:首先膘侮,在存儲過程創(chuàng)建的時(shí)候屈糊,數(shù)據(jù)庫已經(jīng)對其進(jìn)行了一次解析和優(yōu)化。其次琼了,存儲過程一旦執(zhí)行逻锐,在內(nèi)存中就會保留一份這個(gè)存儲過程,這樣下次再執(zhí)行同樣的存儲過程時(shí)表伦,可以從內(nèi)存中直接調(diào)用谦去。
(3)更強(qiáng)的適應(yīng)性:由于存儲過程對數(shù)據(jù)庫的訪問是通過存儲過程來進(jìn)行的,因此數(shù)據(jù)庫開發(fā)人員可以在不改動存儲過程接口的情況下對數(shù)據(jù)庫進(jìn)行任何改動蹦哼,而這些改動不會對應(yīng)用程序造成影響鳄哭。
(4) 布式工作:應(yīng)用程序和數(shù)據(jù)庫的編碼工作可以分別獨(dú)立進(jìn)行,而不會相互壓制纲熏。
由以上的分析可以看到妆丘,在應(yīng)用程序中使用存儲過程是很有必要的。
存儲過程的定義規(guī)范
一局劲,存儲過程的格式:
Create or replace function 過程名(參數(shù)名 參數(shù)類型,…..) returns 返回值類型 as
$body$
//聲明變量
Declare
變量名變量類型勺拣;
如:
flag Boolean;
變量賦值方式(變量名類型 :=值;)
如:
str text :=值; / str text; str :=值鱼填;
Begin
函數(shù)體药有;
return 變量名; //存儲過程中的返回語句
End;
$body$
Language plpgsql;
二,變量類型:
有整數(shù)類型(Smallint,Int等)愤惰,浮點(diǎn)類型(float)苇经,時(shí)間類型(date,time,timestamp,interval),還有其他特殊類型比如inet宦言,point等扇单。
三,連接字符:
Postgresql存儲過程中的連接字符使用的是"||"
四奠旺,控制結(jié)構(gòu):
使用LOOP蜘澜,EXIT,CONTINUE响疚,WHILE鄙信, 和FOR 語句,可以控制PL/pgSQL 函數(shù)重復(fù)一系列命令稽寒。需要使用的時(shí)候請查詳細(xì)資料扮碧。
五趟章,異常捕獲:
EXCEPTION
WHEN 錯誤碼(如:STRING_DATA_RIGHT_TRUNCATION:字串?dāng)?shù)據(jù)右邊被截?cái)啵?THEN
/**后臺打印錯誤信息*/
RAISE NOTICE '錯吳信息';
或者錯誤碼為UNDEFINED_TABLE時(shí)可以執(zhí)行創(chuàng)建表的操作然后在入數(shù)據(jù)杏糙。
存儲過程的示例
例子1:
/**
批量插入一批數(shù)據(jù),經(jīng)緯度字段值要滿足中國地理位置上的經(jīng)緯度范圍蚓土;
注:時(shí)間不能指定為同一時(shí)間宏侍,否則會掃描全表,導(dǎo)致性能低下蜀漆。下列腳本未考慮時(shí)間的分段谅河,采用的一個(gè)時(shí)間點(diǎn)。
*/
create or replace function intobatch() returns integer as
$body$
declare
skyid integer;
lot float;
lat float;
sex varchar;
level integer;
ctime int :=1325404914;
num integer :=0;
total integer :=0;
begin
lot='73.6666666';
lat='3.8666666';
FOR skyid IN 404499817 ..404953416 loop
if(lot > 135.0416666) then
lot=73.6666666;
end if;
if(lat > 53.5500000) then
lat=3.8666666;
end if;
if(skyid%2 <> 0) then
sex='1';
level=0;
else
sex='2';
level=1;
end if;
INSERT INTO user_last_location(user_id,app_id,lonlat,sex,accurate_level,lonlat_point,create_time)
VALUES(skyid,2934,ST_GeomFromText('POINT('||lot||' '||lat||')',4326),sex,level,POINT(lot,lat),to_timestamp(ctime));
lot=lot+0.1;
lat=lat+0.1;
skyid=skyid+1;
end loop;
return skyid;
end
$body$
languageplpgsql;
SELECT *from intobatch();
例子2:此例子是審計(jì)的生產(chǎn)環(huán)境的例子
-- 存儲過程
CREATE OR REPLACE FUNCTION audit_event_partition_trigger()
RETURNS TRIGGER AS $$
DECLARE date_text TEXT;
DECLARE end_date_text TEXT;
DECLARE insert_statement TEXT;
BEGIN
SELECT to_char(NEW.time_event, 'YYYY_MM_DD') INTO date_text;
SELECT to_char(NEW.time_event + INTERVAL '1 DAY', 'YYYY_MM_DD') INTO end_date_text;
insert_statement := 'INSERT INTO audit_event_' || date_text || ' VALUES($1.*)';
EXECUTE insert_statement USING NEW;
RETURN NULL;
EXCEPTION
WHEN UNDEFINED_TABLE
THEN
EXECUTE
'CREATE TABLE IF NOT EXISTS audit_event_' || date_text || '(CHECK ( time_event >= ''' || date_text || ''' AND time_event < '''|| end_date_text ||''' )) INHERITS (audit_event)';
RAISE NOTICE 'CREATE NON-EXISTANT TABLE audit_event_%', date_text;
EXECUTE
'CREATE INDEX audit_event_' || date_text || '_event_msg_body ON audit_event_' || date_text || ' USING gin(event_msg_body gin_trgm_ops); '
|| 'CREATE INDEX audit_event_' || date_text || '_gid ON audit_event_' || date_text || ' USING btree(gid);'
|| 'CREATE INDEX audit_event_' || date_text || '_id ON audit_event_' || date_text || ' USING btree(id);'
|| 'CREATE INDEX audit_event_' || date_text || '_module ON audit_event_' || date_text || ' USING btree(module);'
|| 'CREATE INDEX audit_event_' || date_text || '_access_time ON audit_event_' || date_text || ' USING btree(access_time);'
|| 'CREATE INDEX audit_event_' || date_text || '_mid ON audit_event_' || date_text || ' USING btree(mid);'
|| 'CREATE INDEX audit_event_' || date_text || '_time_event ON audit_event_' || date_text || ' USING btree(time_event);';
EXECUTE insert_statement USING NEW;
RETURN NULL;
END;
$$
LANGUAGE plpgsql
這個(gè)是由觸發(fā)器來引發(fā)執(zhí)行的存儲過程:
DROP TRIGGER IF EXISTS auto_insert_into_audit_event_tbl_partiton ON audit_event;
CREATE TRIGGER auto_insert_into_audit_event_tbl_partiton BEFORE INSERT OR UPDATE ON audit_event
FOR EACH ROW
EXECUTE PROCEDURE audit_event_partition_trigger()
reference
對存儲過程的一些理解
簡單通俗的解釋一下存儲過程是干什么的
分表分庫設(shè)計(jì)