楼主: yulihua49

[PRO*C] 看我做的数据库包装器

[复制链接]
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
71#
 楼主| 发表于 2008-12-8 14:02 | 只看该作者
原帖由 newkid 于 2008-12-7 22:06 发表
说到树的遍历,给你出个题:
http://www.itpub.net/thread-1095473-1-2.html

作者的数据在ETL过程中失去了父子关系,我用SQL重新建立了父子关系,并求出所有根到节点的用量合计。
你用你的方法做做看,把数据弄到C服务器里去遍历、计算,看看效率怎么样?

现在的数据量太少,SQL优势不明显,如果你有兴趣应战我可以提供SQL脚本来灌入几万行数据。

果真高手,佩服。
讲一个故事。
13年前。我们的结帐程序,班结帐,1000多条记录吧,分类成100多个条目。用的group by,order by。
用了40多分钟。后来,改进了索引,取消了order by,2.5分钟。后来,改成在内存的二叉树分组排序,40秒。
现如今,技术已经长足进步,取1000个记录,20毫秒,二叉树排序,不超过20ms,100个记录存数据库,120ms,合计不超过150ms。
我不说谁快谁慢,这个速度完全能满足需求。

[ 本帖最后由 yulihua49 于 2008-12-8 14:06 编辑 ]

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
72#
 楼主| 发表于 2008-12-8 14:16 | 只看该作者
现在的数据量太少,SQL优势不明显,如果你有兴趣应战我可以提供SQL脚本来灌入几万行数据。

OCI程序,那时还没有DAU。过些日子改成DAU,速度不会显著变化的。
测试库,每日5600行数据,6秒左右,每秒890行。包括从母表中读取规则,生成席位。这是微机的速度,将来的小型机,高性能盘阵还要快些。
这基本是极限了,大家应该差不多。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
73#
 楼主| 发表于 2008-12-8 14:38 | 只看该作者
原帖由 newkid 于 2008-12-7 05:58 发表
"还是以我那个程序为例,虽然这里只用到四个字段,但全部字段都是要提取出来送到客户端的,即使有任何变化,都要保证是最新的。"
你的意思是某个模块取得整行数据但只使用其中几个列,再传给其他模块?
PLSQL的思路和这个没有可比性,我很少这样传递数据,但如果实在要这么干,用%ROWTYPE作参数就完全可以实现。


"你尽可以写sum函数啊,我的包装器没有禁止你写复杂的SQL语句,..."
我是顺着你的思路,把“计算”任务从数据库分离出来到应用服务器完成,当然我也不相信你会把SUM移出来,就是一个例子。我就是要说明试图把“计算”拿出来是不可取的,反而会给数据库造成更大负担。

"虽然存储过程写起来比这简单,但我要调用它并bind返回值,语句会比这多,更主要的,程序员必须理解其中的机制,我这程序概念很少。"
我不觉得调用一个过程的机制会有多么复杂,有什么难理解的?不就是个接口吗?


"看了ORACLE的语句池,用常数完全可以的,它要求严格相等的语句,我完全满足这个要求。如果两个客户先后请求了同样的内容,语句分析完全可以绕过。语句生成开销几乎为0,不必考虑。"
你错了。看看你自己的例子:始发日期、车次、上车站、下车站、席别、用途、数量
知道这里面所有字段的所有取值会有多少种组合?两个客户买同一种票的可能性占的比例是多少?而且始发日期每天都不一样!本来一个硬解析可以搞定,你却生成了N种SQL!这样的做法不单浪费CPU,有时候还把优化好的计划给挤出去了,因为再大的共享池也满足不了你。


"领导对小型机的印象已经根深蒂固,轻易不会改变。再说,小型机可以买到服务,一年只要花几百万,系统出什么事,人家立刻派技术人员现场处理,全部责任由厂家负,我们领导就没责任啦!"
既然投资了就要让小型机发挥计算能力,不要把它当作存储设备。

"整个架构方案与ORACLE密切协商的结果,ORACLE承认OCI是最高效的接口,存储过程可能在特定条件下更有效。"
是与ODBC,JDBC相比较吧?
ORACLE销售人员为了卖出单子,肯定会顺着你们的思路,这个我一点都不奇怪。

"新的DAU支持存储过程,但对存储过程还是要慎用。
使用方法:
调用存储过程,bind返回参数,如果有游标 则:..."
太好了,我们可以利用这个功能作对照测试。


"下周给你个功能,你试试吧。我主要怀疑你的存储过程万能论。"
我建议你把你认为最可能发生“堵车”的部分拿出来,我来证明存储过程是如何的顺畅。
我从来没有说过存储过程万能,但存储过程对付密集型事务系统是最佳方案。

“我一直强调的是,本方法编程便捷。就像hibernate,尽管对它的性能有不少质疑,仍获得广泛使用。”
便捷与否,看编程人员的熟练程度。在我看来用文本编辑器写存储过程就很便捷。


"这不需要考虑,几乎所有的数学计算,C语言都要比存储过程快数量级的。以主频2.5G的CPU为例,一条指令仅0.4毫微秒,即每微秒2500条指令,C语言的语句对机器指令有限对应(一个语句对应有限条机器指令)。存储过程(我知道ORACLE可以使用C库,但我指的一般的存储过程)是半编译的,即使简单表达式,内部也具有复杂结构。计算速度能超过C的,只有汇编了。
小型机的主频一般不高,远比INTEL CPU低,造价又那么高,当然不合算。"
存储过程不和C程序拼算法,比的是处理事务的能力。存储过程大量依靠SQL, 你再怎么搞,最终也得生成SQL, 这是绕不过去的。


认证加解密: 去看看DBMS_CRYPTO,里面应有尽有,都是用C实现的。批量数据的加密解密肯定是用SQL调用DBMS_CRYPTO最快,比你一行一行取出来再运算再写回数据库要快。
压缩: 这主要在图像视频处理领域,不是我讲的事务处理。
格式变换(变量-JSON-字符串): 我说过要在数据库之外完成。非得让数据库来做,效率也不低,就是代码看起来比较“脏”。
动态计算方法(比如票价计算,算法随时由业主提出,可能要用一些描述字典来表达): 这绝对是存储过程占优,不信你就和我比试比试。规则(参数)都是存在数据库里的。

链表,树,图(径路计算)等:我很少用链表,事务处理数组足矣。至于树和图,这正是ORACLE的CONNECT BY大显身手的地方,特别是数据越大优势越明显。
看看我出这个题:
http://www.itpub.net/thread-1037629-1-1.html

“哪样存储过程也玩不转”
你错了!


我服了你了,你是高手,按你的方法可能是个好主意,你的活,按你的办法办。
我的活,还得按我的办法办。我们这,你这样的高手找不到的(将来有困难,还要请教哦!先拜师了。),
依据既有技术路线,这个活还得继续干下去。今后的进展我还会来汇报,有兴趣的还可以讨论,我想,不是讨论干不干的问题,而是讨论怎么干的问题,还需要什么功能等等。
现在程序还比较散乱,有人想要,想试试的,我可以打包提供,这还需要一些时间。

关于必要性问题,我和newkid讨论这么久了,观点就在这摆着,我不想说服谁,每人根据自己的实际情况自行选择。

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
74#
 楼主| 发表于 2008-12-8 16:23 | 只看该作者
别忘了我的挑战书,我等着你给我出题呢。

// 登录处理
static int loginProc(GDA *ctx,struct login_s *logrec,DEV_SHIFT_s *dshift,char *tmp1)
{
char stmt[4096],tmp[1024];
int ret;
TUXDEV_s tdev;
TUXUSER_s tuser;
char bc[30];
INT4 crc;
char md5[16];
DAU dev_DAU,ctx_DAU;
INT64 now;
        memset(ctx->contex.userid,0,sizeof(ctx->contex.userid));
        now=ctx->contex.last_oper;
        DAU_init(&dev_DAU,ctx->SQL_Connect,"TUXDEV",&tdev,TUXDEV_type);
        strcpy(tdev.devid,logrec->devid); //检索条件
again:
        ret=getDevShift(&dev_DAU,stmt); //DAO
        if(ret <=0 ) {
                DAU_free(&dev_DAU);
                if(ctx->SQL_Connect->Errno==3114||ctx->SQL_Connect->Errno==-30001) {  //数据库没打开
                        ___SQL_CloseDatabase__(ctx->SQL_Connect);
                        ret=db_open(ctx->SQL_Connect);
                        if(!ret) goto again;
                }
                sprintf(tmp1,"%s:该设备不存在!err=%d,%s",logrec->devid,
                        ctx->SQL_Connect->Errno,
                        ctx->SQL_Connect->ErrMsg);
                return -1;
        }
        DAU_next(&dev_DAU);
/*****************************************************************
*  tdev.clid存在,说明这个终端没有正常终止,应该向TUXEDO咨询一下,
* 其clid是否能查询到状态,是否在线?
******************************************************************/
        DAU_init(&ctx_DAU,ctx->SQL_Connect,"TUXCONTEX",&ctx->contex,TUXCONTEX_type);
        if(tdev.clid) { // 只写日志
                ShowLog(1,"登录冲突,该设备先前的登录作业未完成!");
//是否释放先前占用的席位?
                if(tdev.devtype&1) {
                }
//删除状态,这有点问题,将来WEB服务器是允许一个设备多个连接的
                ret=deleteTuxcontex(&ctx_DAU,tdev.clid,stmt);
                ShowLog(5,"logProc:删除未结束状态,%s,ret=%d",stmt,ret);
                if(ret != 1) {
                        ShowLog(1,"删除该设备先前的状态失败, %s,err=%d,%s",
                                stmt,ctx->SQL_Connect->Errno,
                                ctx->SQL_Connect->ErrMsg);
                }
        }
//检查一下该CA存在否?
        MD5(logrec->CA,(long)strlen(logrec->CA),md5);
        if(!*tdev.devca) {              //CA不存在,加入
                byte_a64(tdev.devca,md5,sizeof(md5));
        } else { //CA存在,核对CA
                byte_a64(tmp,md5,sizeof(md5));
                if(strcmp(tmp,tdev.devca)) {
                        sprintf(tmp1,"CA 错误,nowdevice=%s:%s,db=%s",tmp,logrec->CA,tdev.devca);
                        DAU_free(&dev_DAU);
                        DAU_free(&ctx_DAU);
                        return -4;
                }
        }
// 登录状态写入tuxdev
        tdev.last_log=now;
        tdev.clid=ctx->contex.clid;

        ret= updateDevBill(&dev_DAU,stmt); //DAO
ShowLog(5,"%s,ret=%d",stmt,ret);
        if(ret!=1) {//有人问如何得到update的条数,好像还挺麻烦的,我这里立刻就告诉你。
                DAU_free(&dev_DAU);
                DAU_free(&ctx_DAU);
                sprintf(tmp1,"loginProc:setCA %s",stmt);
                return -2;
        }
        ret=DAU_copy(&ctx_DAU,&dev_DAU,0); //dev同名字段->ctx,将来还可以在tuxdev和tuxcontex添点什么,跟我没关系,copy过去就是。
// 认证用户
        DAU_init(&dev_DAU,0,"TUXUSER",&tuser,TUXUSER_type);//重用DAU
        strcpy(tuser.userid,logrec->uid);
        ret=getUser(&dev_DAU,stmt);//DAO
ShowLog(5,"%s,ret=%d",stmt,ret);
        if(ret <=0 ) {
                sprintf(tmp1,"%s:该用户不存在!err=%d,%s",logrec->uid,
                        ctx->SQL_Connect->Errno,
                        ctx->SQL_Connect->ErrMsg);
                DAU_free(&ctx_DAU);
                DAU_free(&dev_DAU);
                return -3;
        }
        DAU_next(&dev_DAU);
        if(!*tuser.password) { // 建立新口令
                sprintf(tmp,"%lld%ld",now,tdev.clid);
                crc=ssh_crc32(tmp,strlen(tmp));
                tmp[0]=(crc&0x3f)+0x21;
                crc >>= 6;
                tmp[1]=(crc & 0x3f)+0x21;
                des_fcrypt(logrec->pwd,tmp,tuser.password);
        } else {                //核对口令
                des_fcrypt(logrec->pwd,tuser.password,tmp);
                if(strcmp(tuser.password,tmp)) {
                        sprintf(tmp1,"口令错!");
                        DAU_free(&ctx_DAU);
                        DAU_free(&dev_DAU);
                        return -4;
                }
        }
        tuser.last_log=now;
        ret=updateUser(&dev_DAU,stmt);//DAO
ShowLog(5,"%s,ret=%d",stmt,ret);
        if(ret!=1) {
                sprintf(tmp1,"loginProc:setuser %s err=%d,%s",stmt);
                DAU_free(&dev_DAU);
                DAU_free(&ctx_DAU);
                return -5;
        }
        DAU_free(&dev_DAU);
//班次计算
        bcjs(bc,(int)(now/60),tdev.atime,1440-tdev.ptime-15);
//班次中的统计日期截取到contex
        stptok(bc,ctx->contex.stat_date,sizeof(ctx->contex.stat_date)," ");
// 建立 tuxcontex
        strcpy(ctx->contex.username,tuser.username);
        strcpy(ctx->contex.userid,logrec->uid);
        if(tdev.devtype & 2) {          //是帐务终端
                ret=shiftProc(ctx,dshift,bc,tmp1);//班次和票据的设定,还要往ctx添点东西。
                if(ret) {
                        DAU_free(&ctx_DAU);
                        return ret;
                }
        }

        ret=DAU_insert(&ctx_DAU,tmp1);//我怎么看也比insert一大堆列省事。
        DAU_free(&ctx_DAU);
// ShowLog(5,"%s,ret=%d",tmp,ret);
        if(ret) {
                strsubst(tmp1,0,"loginProc:登录失败,不能建立客户状态:");
                sprintf(tmp1+strlen(tmp1),",err=%d,%s",
                        ctx->SQL_Connect->Errno,
                        ctx->SQL_Connect->ErrMsg);
        }
        else sprintf(tmp1,"%s",tdev.devname);
        return ret;
}

不指望谁能用存储过程干这个活,大家看看,剥离了访问逻辑的纯业务逻辑是否好懂?

[ 本帖最后由 yulihua49 于 2008-12-8 17:05 编辑 ]

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
75#
 楼主| 发表于 2008-12-8 16:42 | 只看该作者
原帖由 yulihua49 于 2008-12-8 14:38 发表

"看了ORACLE的语句池,用常数完全可以的,它要求严格相等的语句,我完全满足这个要求。如果两个客户先后请求了同样的内容,语句分析完全可以绕过。语句生成开销几乎为0,不必考虑。"
你错了。看看你自己的例子:始发日期、车次、上车站、下车站、席别、用途、数量
知道这里面所有字段的所有取值会有多少种组合?两个客户买同一种票的可能性占的比例是多少?而且始发日期每天都不一样!本来一个硬解析可以搞定,你却生成了N种SQL!这样的做法不单浪费CPU,有时候还把优化好的计划给挤出去了,因为再大的共享池也满足不了你。

相同的日期、车次、始发站、到达站、席别、用途,就会产生一模一样的SQL语句!
结果集里,车厢号、席位号肯定是不一样的,那是主键的一部分但不是检索条件。
我见过15秒内京沪某车次400张卧铺被抢空!这前后几十个SQL语句肯定是一模一样的。

[ 本帖最后由 yulihua49 于 2008-12-8 16:46 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
76#
发表于 2008-12-9 00:19 | 只看该作者
原帖由 yulihua49 于 2008-12-8 14:02 发表

果真高手,佩服。
讲一个故事。
13年前。我们的结帐程序,班结帐,1000多条记录吧,分类成100多个条目。用的group by,order by。
用了40多分钟。后来,改进了索引,取消了order by,2.5分钟。后来,改成在内存的二叉树分组排序,40秒。
现如今,技术已经长足进步,取1000个记录,20毫秒,二叉树排序,不超过20ms,100个记录存数据库,120ms,合计不超过150ms。
我不说谁快谁慢,这个速度完全能满足需求。


13年前我还在用486作做DOS下的FOXPRO呢,也没听说1000条数据的计算要花40分钟啊?肯定是哪里搞错了。

我举这个例子只是为了表明树的遍历不但不是ORACLE的劣势,反而是优势。试想自己你写代码来实现树的遍历要多少代码?哪怕是C程序,效率也比不上SQL。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
77#
发表于 2008-12-9 00:26 | 只看该作者
原帖由 yulihua49 于 2008-12-8 14:38 发表


我服了你了,你是高手,按你的方法可能是个好主意,你的活,按你的办法办。
我的活,还得按我的办法办。我们这,你这样的高手找不到的(将来有困难,还要请教哦!先拜师了。),
依据既有技术路线,这个活还得继续干下去。今后的进展我还会来汇报,有兴趣的还可以讨论,我想,不是讨论干不干的问题,而是讨论怎么干的问题,还需要什么功能等等。
现在程序还比较散乱,有人想要,想试试的,我可以打包提供,这还需要一些时间。

关于必要性问题,我和newkid讨论这么久了,观点就在这摆着,我不想说服谁,每人根据自己的实际情况自行选择。


我可不敢妄称高手,就是多混了几年饭而已。掌握PL/SQL和SQL比起C, JAVA要容易得多,你们有写getSeat_for_sell这样的人才,改用存储过程一点也不费事,就是一个习惯和观念的问题。

欢迎你继续来讨论!

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
78#
发表于 2008-12-9 00:34 | 只看该作者
原帖由 yulihua49 于 2008-12-8 16:42 发表

相同的日期、车次、始发站、到达站、席别、用途,就会产生一模一样的SQL语句!
结果集里,车厢号、席位号肯定是不一样的,那是主键的一部分但不是检索条件。
我见过15秒内京沪某车次400张卧铺被抢空!这前后几十个SQL语句肯定是一模一样的。


我当然知道,就是所有条件必须一模一样才能产生一模一样的SQL. 可是你这么多的组合,一模一样的可能性太小了。就拿你举的例子来说,你生成的这个SQL最多使用400次,生命周期15秒。在一个设计良好的系统中,SQL应该是终生使用的!别小看一个硬解析,系统忙起来就会要你的命。

假如这个地方还不够说明问题,我们可以来看一个别的例子。你们卖出去的票每张都有一个唯一号吧?假设就叫TICKET_ID. 那么这个TICKET_ID就是绝对不能重用的,凡是有 WHERE TICKET_ID = XXXX 这样的地方,你们必须为每张票生成一个SQL!它们积累起来就是非常可观的开销,会把其他优化好的SQL从共享池挤出去,造成恶性循环。所以说,整个系统从头到尾都必须贯穿绑定变量的思想,否则只要有一个地方疏忽了,一粒老鼠屎就会坏了一锅汤!

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
79#
发表于 2008-12-9 00:39 | 只看该作者
关于这个登录模块,你没有给出数据结构,还隐藏了很多逻辑在 getDevShift,deleteTuxcontex, updateDevBill 等等模块之中,所以我无法写出等价的存储过程。
这个登录模块再怎么样也不应该造成系统堵车,总共几百个终端,每次换班总得四五个小时吧?
以下是我粗略看了一遍的结论,有很多地方我认为都可在存储过程中作而且可以做得更好:

检查终端是否正常终止:如果你在数据库里维护终端状态,在存储过程中完全可以做到。
检查一下该CA存在否:如果要比较的数据都在数据库里,数据库可以作检查。必要的话也可让数据库计算MD5, 但是我倾向于加密后再传入数据库。
登录状态写入tuxdev:updateDevBill完全可在存储过程中实现。如果你愿意在内存中维护一个副本,可在调用成功后自己写入内存的某个地方。
认证用户:getUser完全可在存储过程中实现, 包括核对口令。同上,我倾向于口令加密后再传入数据库。
建立新口令:??为什么在这里会建立新口令?
班次计算:完全可在存储过程中实现。
建立 tuxcontex: 可在调用成功后自己写入内存。ret=DAU_insert(&ctx_DAU,tmp1)在存储过程中做更好。

"不指望谁能用存储过程干这个活,大家看看,剥离了访问逻辑的纯业务逻辑是否好懂?"
用存储过程之后就没有什么访问逻辑、业务逻辑了,你要做的就是准备一系列输入数据,调用一个存储过程,把它的返回结果复制到内存(假如你需要这么做的话)。
至于出错处理,我的方法是从存储过程抛出EXCEPTION, 格式为错误代码:错误信息,你可以在客户端捕获,做一个通用的错误日志模块。
如果用你的方法,看看里面生成了多少SQL, 要和数据库做多少次交互?能比调用一个过程更省事吗?
至于存储过程内部的代码,绝对是很整洁的,愿意的话也可以分小模块。PL/SQL的最大好处就是和SQL无缝接口,它取个数据那可是手到擒来。


再给你挑挑毛病:
用了goto, 这个是做程序员比较忌讳的,就用一个循环不是很好吗?
凡是异常中止的地方,你都有DAU_free。难道没有更好的垃圾回收办法?

[ 本帖最后由 newkid 于 2008-12-9 02:19 编辑 ]

使用道具 举报

回复
论坛徽章:
14
2009新春纪念徽章
日期:2009-01-04 14:52:28沸羊羊
日期:2015-03-04 14:51:52优秀写手
日期:2014-03-14 06:00:13马上有房
日期:2014-02-18 16:42:022014年新春福章
日期:2014-02-18 16:42:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-09 18:08:15蜘蛛蛋
日期:2012-06-27 21:08:142012新春纪念徽章
日期:2012-01-04 11:53:29ITPUB十周年纪念徽章
日期:2011-11-01 16:23:26
80#
 楼主| 发表于 2008-12-9 09:14 | 只看该作者
原帖由 newkid 于 2008-12-9 00:39 发表 [url=http://www.itpub.net/redirect.php?goto=findpost&pid=12347475&ptid=1088197][img]


再给你挑挑毛病:
用了goto, 这个是做程序员比较忌讳的,就用一个循环不是很好吗?
凡是异常中止的地方,你都有DAU_free。难道没有更好的垃圾回收办法?

我就知道这有诟病,但这只是一个极端情况的处理,用while好像更难懂,可以改。
free目前没好办法,JAVA的那种自动回收存在不确定性,再说C也没有提供。

堵车的程序就是2页15楼,你看那个循环没有完,后边应该是占用成功的席位(一行的全部内容)打包加入一个数组。最后返回这个数组。
我不希望你用一个表,然后返我游标,这样一是增加了IO,二是增加了堵车的机会。我的条件里是多选了几条记录,原来是多一倍,只占用请求的数量。可能想选择互相邻近的席位,或靠窗的,吸烟不吸烟的什么的,还没有想好算法,总之会有一些选择余地。这仍然是个DEMO,并非真正的程序。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表