楼主: 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
91#
 楼主| 发表于 2008-12-10 10:22 | 只看该作者
原帖由 newkid 于 2008-12-10 10:05 发表
你15楼有个: if(xb==0) strcat(stmt,"desc ");

席别编码问题,20=硬卧,21=硬卧下,22=中,23=上,0=无号,1=硬座,如果你要无号,那么如果有硬座优先给你。反正价钱一样。

使用道具 举报

回复
论坛徽章:
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
92#
发表于 2008-12-10 10:32 | 只看该作者
看了你那个UPDATE处理,要是个别字段UPDATE又有绑定变量问题。
我先下了,明天继续聊。

使用道具 举报

回复
论坛徽章:
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
93#
 楼主| 发表于 2008-12-10 10:41 | 只看该作者
原帖由 newkid 于 2008-12-10 10:20 发表
呵呵我也不记得具体参数格式,你GOOGLE一下好了。

关于ROWID我还是不理解,如果有人退票你的ROWID从哪里来?难道是打在票上的?
你应该有一个唯一的流水号作主键的。

退票是另一回事。
ROWID很好,一直用的。另外的唯一主键造成双主键,不符合第三范式的。
每个席位唯一的,已经有了控制唯一性的主键。

使用道具 举报

回复
论坛徽章:
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
94#
 楼主| 发表于 2008-12-10 14:57 | 只看该作者
原帖由 newkid 于 2008-12-10 10:05 发表
你15楼有个: if(xb==0) strcat(stmt,"desc ");
所以我有这个:seat_type*DECODE(p_xb,0,-1,1) 作排序,我也不知道你为要这样。

关于索引,同一天发车,同一车次的记录有多少?我自己作了个(START_DATE,TRAIN_NO)的复合索引。WHERE里面如果已经有高效的条件,其他AND条件复杂一些不要紧。

如果你愿意提供测试数据,就用EXP导出DMP再压缩,传到某地方让我下载。


1亿条记录中,有1000个符合条件,从中取几个。

不用临时表,直接生成结果集,过去确实没听说过。不知OCI可否?过去,车是堵在临时表。
你的程序的问题:
构建结果集,要读系统表,与我前边自动建模板干的一样事。select有*号,造成读系统表,与我前边自动建模板干的一样事。
我虽然有动态生成数据结构的功能,但一般不提倡使用,那会有一些开销,就像你上边的程序。

给我游标,我还要FETCH。
再有,你真是高手,有你这水平的,有几个?至少我们公司没有。
你这程序,我看得晕晕乎乎,我的程序,是玩C的都懂。
列名,不是用*就是罗列,如果业务涉及到表多,光罗列列名就不小篇幅,过程调用,也是大规模的参数。我们原来的存储过程动辄几十个参数。
你看我的C程序,多是结构接口,要简便不少。更重要的,数据结构变更,你要修改多少程序?我只要重新生成模板,需要改动程序很少,然后编译,完事。
还有,你很难写工具,我很容易。(有点武断哦,反正我用PRO*C很难弄,玩动态游标太费劲)
如万能数据传输、制表软件、通用统计分析等等,你会面向未知的数据。

关于BIND,不是问题。没测出有什么优势。退一步讲,就算我开销大一些也完全容忍,因为是在APPserver的开销很廉价。

数据库RAC只有几台,APPserver有几十台,终端数万。
术业有专攻,RAC你保证数据吞吐量,APPserver高性能计算,client,优秀的人机界面。

SQL语句的分析问题,充其量是计算问题,不是IO问题,高主频的CPU轻易化解,永远成不了瓶颈。
数据库作黑盒,用了十几年了,性能非常满意,并未出现前面朋友所说的什么惨重代价。

使用道具 举报

回复
论坛徽章:
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
95#
 楼主| 发表于 2008-12-10 15:27 | 只看该作者
原帖由 newkid 于 2008-12-10 02:41 发表
FOR lv_rec IN (SELECT rowid AS row_id,seat.*
                    FROM seat
                   WHERE start_date        = p_start_date
                         AND beg_station   = p_beg_station
                         AND train_no      = p_train_no
                         AND (MOD(p_xb,10) = 0 AND seat_type > p_xb AND seat_type <= p_xb+9
                              OR MOD(p_xb,10) <> 0 AND seat_type = p_xb
                              )
                         AND end_station  >= p_arrive
                         AND purpose      =  p_purpose
                         AND flag         =  0
                   ORDER BY end_station,carno,seat_no,seat_type*DECODE(p_xb,0,-1,1)
                 )
LOOP
       lv_flag := NULL;
       BEGIN
          SELECT flag
            INTO lv_flag
            FROM seat
           WHERE rowid = lv_rec.row_id
           FOR UPDATE NOWAIT;
       EXCEPTION
          WHEN e_locked THEN
               lv_flag := NULL;
       END;



没明白,前边那个FOR lv_rec IN 执行了吗?有结果了?
LOOP又从seat SELECT 一次?

应该前边prepare,后边FETCH吧?每次都SELECT,是否语句分析会比较多?

如果前边没有锁,后边又select,可能你的ROWID已经被别人抢走了,直接的结果就是重票。
如果前边有锁,应该使用隔离级1,这趟车的1000张票咬紧牙关谁也别动。
如果隔离级0,等于没锁(FETCH一条锁一条,你全给突噜出来了,只最后一条是锁定。你检查一下100个人里有重票没有!

正确的做法是,prepare-open时加锁。
以后FETCH一个改一个,改一个存一个,最后COMMIT,输出结果。

研究一下我那个程序:
前边prepare FOR  update
中间 FETCH - UPDATE
最后 FREE = close cursor
最最后,由TUXEDO 进行COMMIT或ROLLBACK

数据:94万席位

[ 本帖最后由 yulihua49 于 2008-12-10 15:54 编辑 ]

seat.rar

1.63 MB, 下载次数: 24

使用道具 举报

回复
论坛徽章:
7
2010数据库技术大会纪念徽章
日期:2010-05-13 09:34:22
96#
发表于 2008-12-10 20:10 | 只看该作者
我很想知道这个包装器如果实现一个类似附件中的功能,该如何实现?

请原谅我没有给出测试数据,你只要说下思路就好。

未命名.JPG (85.32 KB, 下载次数: 71)

未命名.JPG

使用道具 举报

回复
论坛徽章:
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
97#
发表于 2008-12-11 00:15 | 只看该作者
"ROWID很好,一直用的。另外的唯一主键造成双主键,不符合第三范式的。"
额滴神呀!你这是哪里学来的设计理论?ROWID只适用于特定条件下快速定位数据,比如我在一个事务内可以用。
主键应该是一个终生不变的逻辑序号,ROWID是物理地址,是行数据存储的位置,位置是会变的!
给你摘一段TOM的书:

“对于有ROWID 的行(Oracle 中最常见的行“类型”;除了IOT 中的行之外,所有行都有ROWID), 以前
ROWID 是不可变的。插入一行时,会为之关联一个ROWID(一个地址),而且这个ROWID 会一直与该行关联,
直到这一行被删除(被物理地从数据库删除)。但是,后来情况发生了变化,因为现在有些操作可能会导致
行的ROWID 改变,例如:
在分区表中更新一行的分区键,使这一行必须从一个分区移至另一个分区。
使用FLASHBACK TABLE 命令将一个数据库表恢复到以前的每个时间点。
执行MOVE 操作以及许多分区操作,如分解或合并分区。
使用ALTER TABLE SHRINK SPACE 命令执行段收缩。
如今,由于ROWID 可能过一段时间会改变(因为它不再是不可变的),所以不建议把它们作为单独的
列物理地存储在数据库表中。也就是说,使用ROWID 作为一个数据库列的数据类型被认为是一种不好的实
践做法。应当避免这种做法,而应使用行的主键(这应该是不可变的),另外引用完整性可以确保数据的完
整性。对此用ROWID 类型是做不到的,不能用ROWID 创建从子表到一个父表的外键,而且不能保证跨表的
完整性。你必须使用主键约束。”

你前面还在关心数据库独立性,现在却在最关键的地方用了ORACLE特色的ROWID, 再次让我大跌眼镜。

“1亿条记录中,有1000个符合条件,从中取几个。”
你是说每天同一车次1000行?小意思。等会我会作试验。你还有个PURPOSE呢,再加入到索引里面又可筛掉一些。

"不用临时表,直接生成结果集,过去确实没听说过。不知OCI可否?过去,车是堵在临时表。"
当然可以了,这个写在存储过程里,对OCI完全不可见,客户端不关心结果集是怎么来的。
临时表也可以,等会我也会作试验。ORACLE临时表不是临时建立的,这和SYBASE完全不同,你不能用SYBASE的思路。

"构建结果集,要读系统表,与我前边自动建模板干的一样事。select有*号,造成读系统表,与我前边自动建模板干的一样事。"
你错了,只有这个SQL被第一次执行时会有硬解析,以后就存在共享池里了,跟*没什么关系。这就是我为什么强调使用绑定变量。
例子:

game@TEST> select * from games;

Statistics
----------------------------------------------------------
        236  recursive calls
          0  db block gets
         44  consistent gets
          7  physical reads
          0  redo size
       2785  bytes sent via SQL*Net to client
        377  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          8  rows processed

我另外开窗口,建立新连接,运行同样的SELECT *:
game@TEST> select * from games;

Statistics
-----------------------------------------------------
          0  recursive calls        ---------- 没有硬解析了!
          0  db block gets
          8  consistent gets
          0  physical reads
          0  redo size
       2785  bytes sent via SQL*Net to client
        377  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          8  rows processed


"我虽然有动态生成数据结构的功能,但一般不提倡使用,那会有一些开销,就像你上边的程序。"
你用模板的开销是不可避免的;而我用静态SQL是可以避免的。
这就是我为什么建议你甩掉模板生成静态程序。


"给我游标,我还要FETCH。"
你自己的做法照样要FETCH,你自己不是说了嘛:"FETCH一个改一个,改一个存一个"。
我也说过你可以做通用模块动取结果集保存到结构数组(动态取得结构描述,或者用模板生成静态程序),就像PL/SQL DEVELOPER的察看游标功能。

"再有,你真是高手,有你这水平的,有几个?至少我们公司没有。"
这个程序谈不上高明,就是很一般的做法。

"你这程序,我看得晕晕乎乎,我的程序,是玩C的都懂。"
这只是习惯问题。你问问这里的人哪个程序好懂?你这样间接操作数据,比我直接SELECT, UPDATE费解多了。

"列名,不是用*就是罗列,如果业务涉及到表多,光罗列列名就不小篇幅,"
要用到的就列出来,这样明明白白的使用,哪里有错很容易查找。多表连接往往是只取其中某几个列出来用的,你这动不动取全部数据的思路还得改变。

"过程调用,也是大规模的参数。我们原来的存储过程动辄几十个参数。"
我是按照你的getseat_for_sell定义的接口,怎么同样的参数到我这里就多了,在你那里就不多了?每个参数都有它的用途,写整齐点多点注释不就行了?

"你看我的C程序,多是结构接口,要简便不少。"
如果你愿意也可以用OBJECT TYPE作参数,但我不喜欢这么用。平面式的参数更直观易维护。

"更重要的,数据结构变更,你要修改多少程序?我只要重新生成模板,需要改动程序很少,然后编译,完事。"
数据结构变更,我的做法是这样:
输入:增加的数据如果不是必须的,那么我会为存储过程增加带DEFAULT值的参数,这样旧的前台程序还能使用。
输出:我会给游标增加的新列,旧的不变。这样旧的前台程序还能使用,只是它不会取到新字段。
如果新数据是必须的,那么接口的改变就是强制性的,如果运行旧程序就会报错。这是好事情,用你的办法少了数据都不知道!

"还有,你很难写工具,我很容易。(有点武断哦,反正我用PRO*C很难弄,玩动态游标太费劲)
如万能数据传输、制表软件、通用统计分析等等,你会面向未知的数据。"
这些有大量第三方工具可使用,我和你讨论的重点是事务处理,这是没有工具可帮助你的。
在用工具的情况下,仍然有一些高效的SQL必须手工写,才能达到最佳性能。


"关于BIND,不是问题。没测出有什么优势。退一步讲,就算我开销大一些也完全容忍,因为是在APPserver的开销很廉价。"
你又错了!要讲多少次你才能明白?这根本不是应用服务器的开销,就是数据库编译SQL的开销!
http://book.csdn.net/bookfiles/82/100822245.shtml
去看看里面的第二点!还不相信你就去GOOGLE ORACLE 绑定变量。

"SQL语句的分析问题,充其量是计算问题,不是IO问题,高主频的CPU轻易化解,永远成不了瓶颈。"
前面你还说要缓解数据库的负担呢?绑定变量的问题确实是CPU问题,这个不是升级能解决的,基本上你有多少资源都会被吃掉。CPU成瓶颈,后面的IO只好跟着等待,这是绕不过的。

"数据库作黑盒,用了十几年了,性能非常满意,并未出现前面朋友所说的什么惨重代价。"
这是因为你做的项目还不算是真正密集型的OLTP。几百个售票终端实际上是小规模的,互联网应用动不动就是几万人在线。你这个思路不转过弯来,以后迟早会吃苦头。


"没明白,前边那个FOR lv_rec IN 执行了吗?有结果了?"
for lv_rec 执行的只是读,这是不会被写或者锁阻塞的,这个是ORACLE的优点。这个是读出所有满足条件的空票。

"LOOP又从seat SELECT 一次?"
这是试图加锁其中的单独一行。

"应该前边prepare,后边FETCH吧?每次都SELECT,是否语句分析会比较多?"
嘿嘿,这就是PLSQL的优点了,隐性游标,用起来多方便!分析嘛,只有第一次(硬解析)

"如果前边没有锁,后边又select,可能你的ROWID已经被别人抢走了,直接的结果就是重票。"
你错了,我在加锁时没有任何附加条件,用了FOR UPDATE NOWAIT, 因此结果可能是:
1. 成功加锁, 但FLAG=1 (被别人先抢走了),我的程序会跳过,不会重票;
2. 成功加锁, 且FLAG=0,我的程序会选中(抢到票了);
3. 加锁失败,但没有阻塞(出ORA-00054异常),跳过找下一个。


"如果前边有锁,应该使用隔离级1,这趟车的1000张票咬紧牙关谁也别动。"
我不会那么蠢的。我的FOR循环是不加锁的,大家都可以抢。

“如果隔离级0,等于没锁(FETCH一条锁一条,你全给突噜出来了,只最后一条是锁定。你检查一下100个人里有重票没有!”
谁说我只锁一条?循环里每个SELECT FOR UPDATE都会锁住一条新数据(不是说只能保留最近一条),在我提交或回滚之前,本事务占有的行锁别人谁也不能动。你可以简单验证一下:开一个SQLPLUS窗口调用我的过程,但是不要提交,看看游标返回哪些票。再另外开窗口去逐条SELECT FOR UPDATE NOWAIT, 看看我总共锁了几条。不论你用任何方法,你倒是证明重票给我看?
后记:我测试后查了游标返回的票数,和表里FLAG=1的票数都是一样的,绝对没有重票。

另外你用的隔离度的表示法我不太习惯,这是ANSI Isolation Levels:
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE
ORACLE缺省使用READ COMMITTED, 加上其他数据库没有的“读一致”特性,这也是我程序的运行环境。

"正确的做法是,prepare-open时加锁。
以后FETCH一个改一个,改一个存一个,最后COMMIT,输出结果。"
那是你的做法,你的问题在于加了ROWNUM, 不加ROWNUM又会锁太多记录——这下子看出我方法的好处了吧?你的程序在高并发的情况下能抢到精确的票数吗?


"研究一下我那个程序:"
研究过了,结论:不如我的方法。

[ 本帖最后由 newkid 于 2008-12-11 06:15 编辑 ]

使用道具 举报

回复
论坛徽章:
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
98#
发表于 2008-12-11 03:10 | 只看该作者
我把你的数据导入了,总共94万多张票,我按(START_DATE,BEG_STATION,TRAIN_NO)建了索引。我提交了100个JOB让ORACLE同时运行,每个JOB尝试50个不同日期的调用,争夺同一车次(H4或H4A)、同一始发站(SJHP)、席位=22、PURPOSE=0的车票,每次请求5张。这个竞争是远远比现实生活要剧烈得多,有时候必须轮循85张票才订到5张。每次调用完我转换成JSON插入结果表,这是模拟你的输出。

结果是:最长的JOB在10来秒结束,最短的0.5秒就抢到所有的票。总共卖出票数21120(因为不是每个尝试的日期都有票)。

把内存数组改用GLOBAL TEMPORARY TABLE保存结果集,最长的JOB差不多15秒,最短的还是0.5秒。

我希望你能给出其他测试方法。如果条件是错开的,这个程序性能会更好。

[ 本帖最后由 newkid 于 2008-12-11 05:43 编辑 ]

使用道具 举报

回复
论坛徽章:
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
99#
 楼主| 发表于 2008-12-11 09:17 | 只看该作者
原帖由 cuicg 于 2008-12-10 20:10 发表
我很想知道这个包装器如果实现一个类似附件中的功能,该如何实现?

请原谅我没有给出测试数据,你只要说下思路就好。

这正是我前边提出的万能制表和统计分析软件。
首先,建立一个数据表,并非一个统计表对应一个数据库表。而是结构相似的表都在一个数据库表里。
一般的模型是:KEY + item。KEY是属性,由多个列组成,能够唯一确定一行。item基本由一系列数字组成,也可以是其他类型。
凡属性成分相同的表都在一个数据库表里。item,可以由item1 --  item N,比方N=100。
你这张表里有9个item,不妨多加一些,50个吧。
那么KEY属性就是:
表名,区县,企业类型,可以增加一个企业ID,      //最好使用代码
表名用于区别不同的表,比方你这个表就称为信息化设备报表,XXB1,如果还有农机报表,就叫NJB1等等。
合计的企业ID=0;每个企业可以单独的条目,经汇总形成ID=0的条目。
这样,不管你原来item是什么名目,有什么数据关系,都被抽象成“项号”。
至于具体的项目名称,在表格模板里,与数据库无关。
看一下我的工具包,十几年前写的,很方便高效的:
最新的改进是支持HTML表格,文档里没写。
getdb,pdb就是用数据库包装器写的,但是老一代的,不是DAU,实际上是DAU的前身。DAU在它的基础上改进的。
pdb完成统计,getdb提取数据,ctab出表,也可以excel或华表出表。
增加报表,只需增加字典和表格模板,修改格式只修改字典和模板。
如果没有数据库包装,我是写不出这些工具的。

[ 本帖最后由 yulihua49 于 2008-12-11 09:52 编辑 ]

tool.rar

6.68 KB, 下载次数: 18

使用道具 举报

回复
论坛徽章:
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
100#
 楼主| 发表于 2008-12-11 16:00 | 只看该作者
原帖由 newkid 于 2008-12-11 03:10 发表
我把你的数据导入了,总共94万多张票,我按(START_DATE,BEG_STATION,TRAIN_NO)建了索引。我提交了100个JOB让ORACLE同时运行,每个JOB尝试50个不同日期的调用,争夺同一车次(H4或H4A)、同一始发站(SJHP)、席位=22、PURPOSE=0的车票,每次请求5张。这个竞争是远远比现实生活要剧烈得多,有时候必须轮循85张票才订到5张。每次调用完我转换成JSON插入结果表,这是模拟你的输出。

结果是:最长的JOB在10来秒结束,最短的0.5秒就抢到所有的票。总共卖出票数21120(因为不是每个尝试的日期都有票)。

把内存数组改用GLOBAL TEMPORARY TABLE保存结果集,最长的JOB差不多15秒,最短的还是0.5秒。

我希望你能给出其他测试方法。如果条件是错开的,这个程序性能会更好。

purpose不能作为主键。主键只能是上述表结构定义的。你不怕相同的席位因为不同的purpose而重复吗?
我做这个测试有困难,因为经过TUXEDO服务,要登录认证,经过车次查询才能申请席位,步骤要比这多得多,有空我专门写一个demo吧,容我一些时间。

SELECT /* +rule */ to_char(start_date,'YYYY-MM-DD') start_date,beg_station,train_no,run_train,to_char(on_date,'YYYY-MM-DD HH24:MI') on_date,carno,seat_type,seat_no,end_station,shortest_station,purpose,gride,pro,flag,used_dev,used_uid,to_char(used_time,'YYYY-MM-DD HH24:MI:SS') used_time,ROWID
FROM TICKET.SEAT
WHERE start_date = to_date('2008-12-11','YYYY-MM-DD') AND beg_station = 'BHHP' AND train_no = 'H6B' AND seat_type >= 20 AND seat_type <= 29 AND end_station >= 6 AND purpose = 0 AND FLAG=0 AND ROWNUM <= 12 ORDER BY END_STATION,CARNO,SEAT_NO,SEAT_TYPe FOR UPDATE WAIT 10 SKIP LOCKED

最好用上面的SELECT,回来的结果集我好拆包。

今天,遵照大家意见,开发了子模板。
例如,想update seat,只涉及5个字段:

T_PkgType  seat_sub_type[6];
DAU seat_DAU,seat_sub_DAU;


DAU_init(&seat_DAU,ctx->SQL_Connect,"SEAT",&seat,SEAT_type);
        //生成子模板
    patt_copy(seat_sub_type,SEAT_type,"flag, used_dev, used_uid, used_time, ROWID");
        DAU_init(&seat_sub_DAU,ctx->SQL_Connect,"SEAT",&seat,seat_sub_type);


.........

        ret=updateSeat_by_ROWID(&seat_sub_DAU,msg);//seat_DAO.c
生成了:
getxw:stmt=
UPDATE TICKET.SEAT SET(flag,used_dev,used_uid,used_time)=(SELECT 1,'SP0102002','ylh',to_date('2008-12-11 15:00:55','YYYY-MM-DD HH24:MI:SS') FROM DUAL) WHERE ROWID = 'AAAM3iAAFAAAEpkAAw'
,ret=1

关于ROWID,不做持久化对象,只是临时用一下,不超过15分钟,没问题的。在席位表里,另外的唯一ID绝不可用。
任何数据库都有ROWID,不过SYBASE和INFORMIX是数字,表示物理记录号。这在模板里可以处理好,与应用无关。
ROWID是最快的定位方法。

我这模板比hibernat快几个数量级,hibernate能用,我的为什么不能用?
我前边说了,模板处理,每个字段只是一条加法指令、一个类型判断和一个sprintf,根本没什么开销的。

没有模板,你上哪找struct里边的成员?

你那个存储过程很好,我还要弄透彻了,测试好,不排除使用。

性能,比JDBC快,这就足够了。
比ODBC快很多,同样工作,我瞬间完成的任务,ODBC要好几秒。

你那个 lv_rec 哪定义的?上来就可以 FOR 吗?

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

使用道具 举报

回复

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

本版积分规则 发表回复

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