楼主: Younth_0701

[SQL] OCI 线程安全

[复制链接]
论坛徽章:
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
11#
发表于 2021-1-14 10:34 | 只看该作者
本帖最后由 yulihua49 于 2021-1-14 10:59 编辑
newkid 发表于 2021-1-13 23:00
先来说说这个“大规模插入操作”。如果数据本来就在库里面,那么INSERT...SELECT是最佳。ETL的T操作有时候 ...

“如果数据本来就在库里面,那么INSERT...SELECT是最佳。ETL的T操作有时候会有很复杂的逻辑,那么这个SELECT可就大显身手了,可以连接,可以聚合(GROUP BY),可以并行跑,可以直接路径加载,等等。”

一般是,但是我用的架构可以超越这个性能:

采用BULKselect,分组(每组1000),分发到多个服务器,每个服务器多核多线程。进行计算,结果insert或update。多线程批量并行。性能超过select......insert........, 即使后者不进行任何计算。性能也超越sqlldr。

“如果数据是在库外面,比如说文本文件,但是文件能上传到数据库服务器,那么就可以定义外部表,把文件当作表来访问,INSERT...SELECT继续大显身手。”

这个方案当年试过,太慢。团队所有方案都测试过,才选用了我的方案。

“如果文件在客户端,那么用ORACLE提供的SQL LOADER,也是OCI接口,成熟又强大,不需要自己写代码。”
这个也一直在用。但是一个场合,需要在加载前先处理一下,就不得不用OCI了。
http://www.itpub.net/thread-1738533-1-1.html


使用道具 举报

回复
论坛徽章:
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
12#
发表于 2021-1-14 11:11 | 只看该作者
本帖最后由 yulihua49 于 2021-1-14 21:39 编辑
Younth_0701 发表于 2021-1-7 12:48
一般是pro*C 内直接写PL/SQL然后预处理编译,这比调用存储过程效率要高。

http://www.itpub.net/forum.php?m ... orid=8804348&page=2
15楼。
OCI比proc快。

看2楼的OCI包装器程序,只有76行,16楼PROC490多行。
看3楼的生成语句,手写还真费事。

使用道具 举报

回复
论坛徽章:
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
13#
发表于 2021-1-14 22:28 | 只看该作者
yulihua49 发表于 2021-1-14 10:34
一般是,但是我用的架构可以超越这个性能:采用BULKselect,分组(每组1000),分发到多个服务器,每个服务 ...

按你的说法,把数据取出来拿到数据库外面“计算”一番再写回去,比直接在数据库内部表对表复制还快?你们的数据库测试开启并行操作了没?我怀疑你们当年的测试就没搞对。
现在时过境迁,死无对证,就当个故事听听吧。

使用道具 举报

回复
论坛徽章:
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
14#
发表于 2021-1-15 15:16 | 只看该作者
本帖最后由 yulihua49 于 2021-1-15 19:44 编辑
newkid 发表于 2021-1-14 22:28
按你的说法,把数据取出来拿到数据库外面“计算”一番再写回去,比直接在数据库内部表对表复制还快?你们的 ...

确实如此。
在外边是全并行计算,用了3台服务器,96个线程。数据库是2台RAC。
从文件--发送--多路并行计算-----多线程并行数组插入,比直接sqlldr(单线程)快,约2,5倍。

select ----发送----并行计算---多线程数组并行update,比在服务器直接update快。
计算是进行一个复杂计算,直接update只改一个字段的值。加parallel没用,产生无数垃圾线程,更慢。


简单说一下这个业务:
北京地铁,当时300多个站,现在500多。
每个站不时吧检票信息传送上来,少则1条,多则一万多一个包,有时一次来几十个包。这些以文件方式到达,必须在规定时限内收走。这些数据不保证不重复,所以进入数据库时必须对重复数据进行标记。不重复的数据被下一个工序清算。
这个阶段,就需要那个1000个in的程序,对每个数据进行判决,速度必须快,要求是每秒5000.
考虑了如下办法:
插入,重复了剔除。批量插入,一旦发现重复记录就会失败,而且不知道哪里失败了,再进行单条插入,效率极低。
查询,发现重复的进行标记,然后插入。我们采用此法。关键字有三部分组成:卡号,检票机号,检票时间。
如果利用这个关键字逐条查询,即使绑定变量,即使不关闭游标,每次仅进行reopen+bindKEY+FETCH,也只能每秒1500个,无法满足需求。
所以就有了那个帖子,1000个KEY,一次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
15#
发表于 2021-1-15 19:56 | 只看该作者
本帖最后由 yulihua49 于 2021-1-15 20:28 编辑
yulihua49 发表于 2021-1-15 15:16
确实如此。在外边是全并行计算,用了3台服务器,96个线程。数据库是2台RAC。从文件--发送--多路并行计算--- ...

现在来说一说不重复的数据下一步的清分操作:
分期分批提取打包成文件,传送到另一个域,这里有单独的服务器和数据库。
对于这些数据(用户数据,UD),根据进站地点、进站时间、出站地点、出站时间,参照运行图,猜一猜,他走的哪条路。
然后,按照途径的各条线的距离,按比例分劈票款。每条线是一个清算单位,个别线路是两个。
运行图阶段性送达。对于读入每一个UD,如果相应时间的运行图未到达,标记为“未处理”。已送达的,进行径路计算,分账。一批处理完,insert。每批一个线程。
每一批运行图到达,收妥,更新每一个服务器内的运行图,然后进行“反刍”,就是把所有未处理的数据再次从数据库中select出来,1000个一批,分发到各个服务器,各个线程,进行计算,结果批量update。
每日0点后的某个时刻对前一天交易进行日结。

架构是:
所有收集的数据文件在通信服务器,同时也是交易管理器,控制着整个交易流程。
它接受UD和运行图,及其他数据。把UG分包,1000个一包,分发到后台的3台计算服务器,各32核。以96线程进行并行计算。然后送到后边2RAC节点的数据库。
反刍也是由这个交易管理器来控制。

日结后,数据被提取出来送往该去的地方,就用到了“oci确实比存储过程快”的那个程序。
http://www.itpub.net/thread-1738533-1-1.html


使用道具 举报

回复
论坛徽章:
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
16#
发表于 2021-1-15 21:51 | 只看该作者
要忽略重复数据而不出错,方法有好几种,你可以用MERGE, 可以简单加一个 /*+ ignore_row_on_dupkey_index */ 的提示,可以加个 DML ERROR LOG (这样还可以知道哪些行出了错误),总之,你们应该多钻研数据库原有的功能。
至于那个并行的问题,也可以手工实现数据分片的,具体问题具体分析。
再说说这个“清算”,其实这些复杂计算都可以事先算好存放起来,用起点,终点,时段,时长作为配置参数,只要匹配上就获得事先算好的分摊比例,不就是一个JOIN的事嘛!你们偏要开发一个AI程序去猜测用户的路线,累不累?

使用道具 举报

回复
论坛徽章:
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
17#
发表于 2021-1-16 20:00 | 只看该作者
本帖最后由 yulihua49 于 2021-1-16 20:56 编辑
newkid 发表于 2021-1-15 21:51
要忽略重复数据而不出错,方法有好几种,你可以用MERGE, 可以简单加一个 /*+ ignore_row_on_dupkey_index * ...

这个我管不了,这个猜测法,是业主几年的设想,之前已经请同济大学研究了算法。他们在实现这个算法的时候,发现太慢。那个399万记录的数据(后来每天超过1000万了),清算一遍是11个小时,完全没有办法事先算好。然后他们找到我,看我能不能解决。经过对项目的研究,我认为可以解决,就应聘了。条件是,不要(不允许)我管算法,只要我把任务调度开,并行做起来即可。经过半年的工作,最后的结果,是两分半算完,现场计算。累不累是同济大学的事,业主花钱了,他们给了算法。

去重的问题,不是重复的不插入,而是只做标记,数据还是要的。
前边我说的流程是简化的,实际要复杂的多。包括,数据包与数据库的重复,包与包的重复,包内数据重复(几十个线程并行,想想有多复杂)。而且,判重的对象涉及6个不同结构的表(后来据说增加了)。
我就是一个程序处理所有需要判重的表,这也算是“通用”的一种方式吧?

使用道具 举报

回复
论坛徽章:
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
18#
发表于 2021-1-16 20:19 | 只看该作者
本帖最后由 yulihua49 于 2021-1-16 21:37 编辑
newkid 发表于 2021-1-15 21:51
要忽略重复数据而不出错,方法有好几种,你可以用MERGE, 可以简单加一个 /*+ ignore_row_on_dupkey_index * ...

稍微介绍下业务:
一个UD,就是那4个参数(起点,时间,终点,时间)有用。两点间的路径是事先算好的,最多5条。在这5条里猜猜走的哪条。
可以正推,也可以倒推,一般倒推靠谱。一共有4种推法,我忘了,就记得4种分两类,两个正推,两个倒推。由算法决定采用哪个推法。
对于每条路径,以倒推为例:
根据出站时间,扣除站内行走时间,匹配出下车时刻,这就确定了是哪个车次下来的。找到这个车次的换乘站时刻,就知道上车时刻,扣除换乘时间,匹配前一个车次的下车时间。就这样,一个个区段的倒推,直到进站的上车时刻,加上进站走行时间,与进站时刻有个差值,这个差值是个参数,用于最后的评估。这个差值还需要试探分劈到经由的各个换乘站(在哪个换乘站没挤上车,走了下一趟车,称为“留乘”)。就这一条路径,以不同留乘方案计算好几次,评估出一个方案提交备选。
若干路径全部提交,再由一个评估程序最终确定走行路径。在这个算法里,所有辅助数据常驻内存,整个计算过程完全在内存进行,纯消耗CPU。
一般每个线程每次处理1000个数据,处理完了批量insert或update(反刍)。整个处理时间一般是250ms左右。
每天1000万,你用SQL整整看,还一条SQL语句单线程做?
最恶劣情况,由于故障,一天没来数据,一天结束收车后,数据一起来。3个小时要完成所有工作,这个只是其中一环,不能3个小时都给我吧!所以当时提的要求是无论如何不能高于3小时。






使用道具 举报

回复
论坛徽章:
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
19#
发表于 2021-1-16 21: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
20#
发表于 2021-1-17 10:48 | 只看该作者
本帖最后由 yulihua49 于 2021-1-17 11:21 编辑
newkid 发表于 2021-1-16 21:58
我说的“事先算好”,是指分摊比例表,目的正是为了解放那几百上千万的计算量,你却理解为要把这几百上千万 ...

你说的不错。本来他就是这种算法。从08年以来都是这个算法,有一个名字:两阶段双比例。第一个阶段,按照5条路径的权重比例分拨,第二阶段,按照各条线路的里程比例分拨。
后来各家对清算的结果不满意,所以才提出了上述算法(称为CMS)。实际上,当所有评估方法失败,CMS就采用两阶段双比例方法。CMS还有更重要功能:统计每个车次每个区段的客流。以前这个客流完全凭人工采样。只能统计各站出入客流。车次区段客流完全是胡扯。cms的正确性大约是70%。他的算法有缺陷,但是我无权改变之。我认为可以提升到90%。上海人的模型对北京不太适合,北京的换乘路径太长,一个因素:最少换乘,没有被考虑。各站换乘走行时间表是有的,仅用于推算车次换乘,并未用于算法。那时我每天地铁上下班,然后查我自己的票,看算对了没有。其他同事也是。对于算错的原因也做了些思考。如果每天沿固定径路走,两阶段双比例肯定乱拨。这活儿挺有意思的,是我的大玩具。
现在不必讨论哪种算法更好,就讨论CMS方法的实现,用什么技术更好。

使用道具 举报

回复

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

本版积分规则 发表回复

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