楼主: yulihua49

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

[复制链接]
论坛徽章:
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
131#
发表于 2008-12-19 00:25 | 只看该作者
"结论:与SQL*loader相比,模板系统开销稍大,……"
你错了,开销不在模板,模板就是初始化的时候用一下(我没仔细看你的程序,但你不会每行都用模板吧?那是很笨的办法)
SQL LOADER也有模板,就是它的控制文件,当然它的功能非常之强大,这你是赶不上的。


"但它带来的程序便利性、可维护性是值得的。"
没看出来?我用SQL LOADER也很便利,很好维护啊?


"尤其写这种通用软件,如果你用PL/SQL写,非要高超技巧不可。"
已经有很好的工具为什么还要用PL/SQL写?
当然,在特定的需求下,用PLSQL写通用代码,即读取系统字典再生成SQL动态执行,这是可行的,我也这么干过,不需要什么高超技巧。程序也比你这堆C源码好读,因为PLSQL天生和数据库是无缝接口的。


"上述程序,loadfile是应用逻辑,insrec()和updaterec()是访问逻辑(DAO)。
单看loadfile,是不是逻辑很清晰易懂?对程序员降低了要求?"
最好的代码就是——没有代码!
直接用SQL LOADER, 不要再写什么代码。


如果你认为用你的loadfile在效率、便利性、可维护性、或者复杂的处理逻辑方面可以超过SQL LOADER+PLSQL后续处理,欢迎你把需求提出来较量。只要是数据处理相关的,我的擂台长期有效,随时恭候。

使用道具 举报

回复
论坛徽章:
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
132#
发表于 2008-12-19 03:15 | 只看该作者
关于那个INSERT+LOSS的试验,我把控制文件的TRUNCATE改为APPEND(这样就会重复插入), 在SQLLDR的命令行加了两个参数:
silent=FEEDBACK ERRORS=10000

差不多花了50秒。所有被拒绝数据被写在tj01.bad文件中。确实比成功的时间要多得多。

使用道具 举报

回复
论坛徽章:
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
133#
发表于 2008-12-20 02:21 | 只看该作者
唉,我吃饱撑的看了你的代码,不幸被我言中了,你竟然是逐行套用模板的。
这个模板解析是你自己的“软解析”过程,应该尽量避免。假如对文件的数据循环,模板解析就应该发生在循环外面。
至于循环里边,也不是一行INSERT一次,最佳办法是用BULK BIND,参见我给你的链接。
至于INSERT+LOSS为什么那么慢,我猜想是回滚的原因。你自己虽然没有作回滚,为了保证SQL语句的原子性,内部有一个回滚操作。回滚是INSERT的逆操作,有多少出错SQL就回滚多少次,所以速度就很慢了。

使用道具 举报

回复
论坛徽章:
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
134#
 楼主| 发表于 2008-12-20 19:46 | 只看该作者
原帖由 ccecmxl 于 2008-12-18 16:19 发表
大体看完了楼主和newkid的高论,感觉楼主被“坑”了,楼主的意思是不用存储过程,用自己写的程序包,感觉相当于自己写了一个pl/sql的引擎。于是就变成了

楼主自己开发的引擎好用,还是oracle自己开发的好用,这点好像没什么争论,我更

倾向于oracle方面,毕竟是他们自己做的系统,各种资源的调配更得心应手。newkid

的意思是如果oracle提供给我们的工具,尽量去用,要充分发挥数据库的优势

(oracle有些方面优势很明显)。而不要把oracle的已经实现的功能自己再实现一遍,

这往往会适得其反。这也是tom的观点(tom应该比与楼主公司交流

的oracle技术人员更权威)。然后希望itpub上这种帖子越来越多。感谢二位提供给我们这么好的学习机会。


这个东西既不是‘引擎’,也不是‘驱动’,那是不能绕过的。我这仅仅是个包装工具,你如果必要是可以绕过的,就像我上边的代码。
另外,前几页有个模板生成的例子,就是要说明可以写ORACLE的特色语句,使用这个工具完全可以使用任何数据库的优势技术。如果要求不高,完全可以十分简便透明的使用数据库。朴素一点说,使用这个工具就是要不写列名!这是程序员最初的要求,能否一句话插入一行数据?以至于有人竟然用JDBC读数据,而用hibernate写数据,原因就想一句话解决问题。具体一些,我这个程序根本就写不出列名,因为我根本不知道要加载什么表!

使用道具 举报

回复
论坛徽章:
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
135#
 楼主| 发表于 2008-12-20 20:06 | 只看该作者
原帖由 newkid 于 2008-12-20 02:21 发表
唉,我吃饱撑的看了你的代码,不幸被我言中了,你竟然是逐行套用模板的。
这个模板解析是你自己的“软解析”过程,应该尽量避免。假如对文件的数据循环,模板解析就应该发生在循环外面。
至于循环里边,也不是一行INSERT一次,最佳办法是用BULK BIND,参见我给你的链接。
至于INSERT+LOSS为什么那么慢,我猜想是回滚的原因。你自己虽然没有作回滚,为了保证SQL语句的原子性,内部有一个回滚操作。回滚是INSERT的逆操作,有多少出错SQL就回滚多少次,所以速度就很慢了。

岂止是每行使用模板,每个字段都要用的!否则,你怎样找到结构里的成员呢?
但这个开销不占多少比例的,例子中大约 0.2秒的开销,主要还是在sqlora上,模板操作的具体代码前边我给你的链接的文章里有,很简单:找地址,一条加法,p=rec+tp〔i〕.offset;一个case语句,判断类型,一个springf语句,没什么开销的,尤其是,没有竞争性开销。C的速度,不是其它解释语言和半编译语言可比的。还是这个问题,hibernate能用,我为什么不能用,它的模板也是每个列都要用的而且要分析和引用类里的方法才能找到成员,而且有竞争性开销(new和垃圾收集),我比它强至少两个数量级。

你发现insrec的代码,比PL/SQL还要优化?游标(sth)一旦打开,以后就根本没有SQL语句了,引擎连寻找语句池的工夫都省了,我们的例子,节省了30%的时间。

ctl文件还是对列名列表了,可以认为是个手工模板。
你说的load append什么意思?追加?追加就错了。如果一行数据存在,就要用新数据覆盖之。我的逻辑你应该看的很明白呀.
数据加载只是个例子,这种通用的活还很多,这个东西要衍生出很多半通用或专用的工具。未来我们有数不清的需求你不编程都能实现?
比方按时间戳加载,在在数据库和加载文件之间,谁的时间戳新就加载谁。
比方按同步标志卸载和加载,比方按时间段加载,在加载数据和被加载数据之间时间段如果不重合,那就要重新分段等等。它们的表名和结构都不确定(会有不止一个表),只能确定部分加载属性,你用SQLload怎么解决?
最好的程序是不写程序!这是我的信条,我经常宣传这个观点。我为什么写通用程序?就是要让别人不写程序,实在不行就少写程序,少改程序,这个系统就是这个思路的产物。

bind问题已经有了结论,感谢这次讨论,bind功能将加入到下一个版本的模板系统。
之所以让你看那个完整源码,不是说要写一个load,而是说我们可以方便的实现一个应用功能而完全不使用SQL,我可以完全不知道数据结构,实现了完全的数据与程序独立,实现了完全的业务逻辑与访问逻辑的分离,应该从这个高度上看问题,而不是关注你有何必要写一个loader。
这个loader短说是为了测试bind,长说是为了上面的原因。还有前边的模板生成,功能不重要,用途也不重要,重要的是,这个系统可以方便的使用任何SQL语句。这个系统支持你使用每种数据库的特征。你可以看一下那个模板生成,在ORACLE是一大堆decode,在SYBASE是一大堆case,支离破碎的SQL很好改的,那个完整的SQL很晕的。


关于席位分配策略,不管效率是否优化,后一个方案是可取的,它更接近我们需求,对这个方案今后要进行测试。

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

使用道具 举报

回复
论坛徽章:
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
136#
发表于 2008-12-21 01:09 | 只看该作者
"朴素一点说,使用这个工具就是要不写列名!......我这个程序根本就写不出列名,因为我根本不知道要加载什么表!"
这是缺点,不是优点。当然这是我们搞数据库的人的观点。

"这是程序员最初的要求,能否一句话插入一行数据?"
一个INSERT罢了,有什么难的。

"你发现insrec的代码,比PL/SQL还要优化?游标(sth)一旦打开,以后就根本没有SQL语句了,引擎连寻找语句池的工夫都省了,我们的例子,节省了30%的时间。"
但是你的INSREC是在LOADFILE循环调用的呀? 你每一行都要调用INSREC, 每次都重新打开游标,重新生成SQL!
(后记: 我发现你sth用的是static, 确实是可以重复利用的, 是我弄错了)

PL/SQL是真正的CACHE游标(即使关闭了也是假关闭,后面还可再次利用),而且对程序员是透明的,使用更为方便。其他语言无法做到。


"你说的load append什么意思?追加?追加就错了。如果一行数据存在,就要用新数据覆盖之。我的逻辑你应该看的很明白呀."
我说过了,覆盖可用MERGE INTO来实现。先加载到临时表,再MERGE INTO. 比你逐行判断好。
最好的办法是用外部表,把文本文件上传到ORACLE服务器,直接MERGE INTO.

"数据加载只是个例子,这种通用的活还很多,这个东西要衍生出很多半通用或专用的工具。未来我们有数不清的需求你不编程都能实现?
比方按时间戳加载,在在数据库和加载文件之间,谁的时间戳新就加载谁。
比方按同步标志卸载和加载,比方按时间段加载,在加载数据和被加载数据之间时间段如果不重合,那就要重新分段等等。它们的表名和结构都不确定(会有不止一个表),只能确定部分加载属性,你用SQLload怎么解决?"
随便什么需求,只要你提出来就可以解决。SQLLOADER/外部表+存储过程。集合操作,绝对最高效,最少代码。

"最好的程序是不写程序!这是我的信条,我经常宣传这个观点。"
我前面也说过。你上面说的复杂需求,你的通用写程序要如何实现?举个例子看看。

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

使用道具 举报

回复
论坛徽章:
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
137#
 楼主| 发表于 2008-12-21 17:47 | 只看该作者
原帖由 newkid 于 2008-12-21 01:09 发表
"但是你的INSREC是在LOADFILE循环调用的呀? 你每一行都要调用INSREC, 每次都重新打开游标,重新生成SQL!

你没看清楚那个insrec?ins_sth一旦打开,就不是-1了,程序进入reopen,只bind,没有语句了。
     if(ins_sth==SQLO_STH_INIT) {
//第一次走这
            ...................................
      } else {
//以后都走这
                ret=sqlo_reopen(ins_sth,bindnum,(CONST char **)argv);
        }


updaterec一样。
程序最后关闭游标。关闭之后再次使用,就要用到ORACLE的CACHE CURSOR了。

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

使用道具 举报

回复
论坛徽章:
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
138#
 楼主| 发表于 2008-12-21 17:55 | 只看该作者
原帖由 newkid 于 2008-12-21 01:09 发表
"你说的load append什么意思?追加?追加就错了。如果一行数据存在,就要用新数据覆盖之。我的逻辑你应该看的很明白呀."
我说过了,覆盖可用MERGE INTO来实现。先加载到临时表,再MERGE INTO. 比你逐行判断好。
最好的办法是用外部表,把文本文件上传到ORACLE服务器,直接MERGE INTO.

复杂点了吧?还能有我这个程序快?

使用道具 举报

回复
论坛徽章:
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
139#
 楼主| 发表于 2008-12-21 18:05 | 只看该作者
原帖由 newkid 于 2008-12-21 01:09 发表
"朴素一点说,使用这个工具就是要不写列名!......我这个程序根本就写不出列名,因为我根本不知道要加载什么表!"
这是缺点,不是优点。当然这是我们搞数据库的人的观点。

"这是程序员最初的要求,能否一句话插入一行数据?"
一个INSERT罢了,有什么难的。


INSERT INTO tabname (什么来着?我忘了,或者,根本不知道) VALUES (天哪,我哪知道是什么呀);
只有你舒服。
ret=DAU_insert(&_DAU,buf);
舒服吗?
很快,DAU_insert就会支持insrec的全部功能,那些bind功能,程序员不用管了。

[ 本帖最后由 yulihua49 于 2008-12-21 18:21 编辑 ]

使用道具 举报

回复
论坛徽章:
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
140#
 楼主| 发表于 2008-12-21 18:16 | 只看该作者
原帖由 newkid 于 2008-12-21 01:09 发表


"数据加载只是个例子,这种通用的活还很多,这个东西要衍生出很多半通用或专用的工具。未来我们有数不清的需求你不编程都能实现?
比方按时间戳加载,在在数据库和加载文件之间,谁的时间戳新就加载谁。
比方按同步标志卸载和加载,比方按时间段加载,在加载数据和被加载数据之间时间段如果不重合,那就要重新分段等等。它们的表名和结构都不确定(会有不止一个表),只能确定部分加载属性,你用SQLload怎么解决?"
随便什么需求,只要你提出来就可以解决。SQLLOADER/外部表+存储过程。集合操作,绝对最高效,最少代码。

"最好的程序是不写程序!这是我的信条,我经常宣传这个观点。"
我前面也说过。你上面说的复杂需求,你的通用写程序要如何实现?举个例子看看。


我说的是半通用,就是所有这类表都要有一个或几个标准名称的字段,比如同步标志,时间戳,分段标志等几个字段。其余的字段就爱啥啥了。
一般情况,先读文件再读库,比较几个特定字段,决定如何处理。就这几个特定字段需要特别写的,所以不是通用的,而是半通用的。

其它字段都是不需要写的,DAU还提供一系列提取和存储未知结构的工具。

使用道具 举报

回复

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

本版积分规则 发表回复

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