如何理解postgresql的存储过程

在b/s系统的构建过程中,数据库操作几乎成为了一个必不可少的操作。调用存储过程实现数据库操作使很多程序员使用的方法,而且大多数的程序员都是能使用存储过程就使用存储过程,很少直接使用sql语句,所以存储过程是很有用而且很重要的。

存储过程简介

存储过程的定义:完成一定功能的可重复调用的程序

简单的说,存储过程是由一些sql语句和控制语句组成的被封装起来的过程,它驻留在数据库中,可以被客户应用程序调用,也可以从另一个过程或触发器调用。它的参数可以被传递和返回。与应用程序中的函数过程类似,存储过程可以通过名字来调用,而且它们同样有输入参数和输出参数。

根据返回值类型的不同,我们可以将存储过程分为三类:返回记录集的存储过程,返回数值的存储过程(也可以称为标量存储过程),以及行为存储过程。顾名思义,返回记录集的存储过程的执行结果是一个记录集,典型的例子是从数据库中检索出符合某一个或几个条件的记录;返回数值的存储过程执行完以后返回一个值,例如在数据库中执行一个有返回值的函数或命令;最后,行为存储过程仅仅是用来实现数据库的某个功能,而没有返回值,例如在数据库中的更新和删除操作。

存储过程的通俗解释:你使用手机拨打A同事的手机,需要一个一个号码的输入,然后才能拨打
而如果你把这个号码设置为快速拨号,那么你只要长按1(自己设置的数字键)就可以直接拨打电话了
把这个号码设置为快速拨号的过程你就可以理解为创建存储过程。

使用存储过程的好处

相对于直接使用sql语句,在应用程序中直接调用存储过程有以下好处:

(1)减少网络通信量。调用一个行数不多的存储过程与直接调用sql语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行sql语句,那么其性能绝对比一条一条的调用sql语句要高得多。

(2)执行速度更快。有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。

(3)更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。

(4) 布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。

由以上的分析可以看到,在应用程序中使用存储过程是很有必要的。

存储过程的定义规范

一,存储过程的格式

Create or replace function 过程名(参数名 参数类型,…..) returns 返回值类型 as
                   $body$
 
                            //声明变量
                            Declare
                            变量名变量类型;
                            如:
                            flag Boolean;
 
                            变量赋值方式(变量名类型 :=值;)
                            如:
                            str  text :=值; / str  text;  str :=值;
 
                            Begin
                                     函数体;
 
                             return 变量名; //存储过程中的返回语句
 
                            End;
                   $body$
         Language plpgsql;

二,变量类型
有整数类型(Smallint,Int等),浮点类型(float),时间类型(date,time,timestamp,interval),还有其他特殊类型比如inet,point等。
三,连接字符
Postgresql存储过程中的连接字符使用的是"||"
四,控制结构
使用LOOP,EXIT,CONTINUE,WHILE, 和FOR 语句,可以控制PL/pgSQL 函数重复一系列命令。需要使用的时候请查详细资料。
五,异常捕获

EXCEPTION
WHEN 错误码(如:STRING_DATA_RIGHT_TRUNCATION:字串数据右边被截断) THEN
        /**后台打印错误信息*/
        RAISE NOTICE '错吴信息';

或者错误码为UNDEFINED_TABLE时可以执行创建表的操作然后在入数据。

存储过程的示例

例子1

/**
批量插入一批数据,经纬度字段值要满足中国地理位置上的经纬度范围;
注:时间不能指定为同一时间,否则会扫描全表,导致性能低下。下列脚本未考虑时间的分段,采用的一个时间点。
*/
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:此例子是审计的生产环境的例子

-- 存储过程
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

这个是由触发器来引发执行的存储过程:

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
对存储过程的一些理解
简单通俗的解释一下存储过程是干什么的
分表分库设计

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容