oracle挂证多少钱一个月_惊呆,一条sql竟然把Oracle搞挂了
一条sql就能把oracle搞挂了,真的是不敢相信啊,前几天生产上确实出现了这样一个故障,我们来一起做一个事件回放。
系统介绍
系统架构见下图:
file
application1和application2是一个分布式系统中的2个应用,application1连接的数据库是database1,application2连接的数据库是database2,application2生产的数据要给application1做跑批使用。
application1要获取database2的数据,并不是通过接口来获取的,而是直连database2来获取,因此application1也具有database2库的读权限。
database2中有1张表table_b,里面保存的数据是application1跑批需要的数据。application1查找到table_b的数据后,先保存到database1的数据库表table_a中,等跑批时取出来用。
table_a和table_b的表结构如下:
file
2个表的主键都是字段a,application1查询出table_b的数据后,会根据主键a来判断这条数据是否存在,如果数据存在,就更新,否则,就插入。
application1使用的orm框架是mybatis,为了减少应用和数据库的交互,使用了oracle的merge语句。
注意:mybatis相关的文件有5个:
TableAMapper.java
TableBMapper.java
TableAMapper.xml
TableBMapper.xml
TableAEntity.java
熟悉mybatis的同学应该都知道,前两个java类是sql操作接口类,第3、4两个文件是存放sql的xml文件,跟前两个文件对应,最后一个java文件是do类。
事故现场
TableBMapper中有一个方法selectForPage,用来按页查询table_b中数据,每页1万条数据,之后把这个list结果merge到table_a,看一下代码:
//从table_b按每页1万条来查询数据
List list = tableBMapper.selectForPage(startPage, 10000);
//把查到的数据一次性merge到table_a中
tableAMapper.mergeFromTableB(list);
我们再看一下TableAMapper.xml中的mergeFromTableB方法,代码如下:
MERGE INTO table_a ta USING(select #{item.a} as a,#{item.b} as b,#{item.c} as c, #{item.d} as c from dual) tb
on (ta.a = tb.a)
WHEN MATCHED THEN UPDATE set
ta.b=tb.b,
ta.c=tb.c,
ta.d=tb.d
WHEN NOT MATCHED THEN insert(
a,
b,
c,
d
)
values (
tb.a,
tb.b,
tb.c,
tb.d
)
注意:为了文章排版,我对表结构做了简化,真实案例中table_a这张表有60多个字段。
这条sql执行后,我截取部分oracle的日志,如下:
file
图中可以看到oracle报了ORA-07445错误。
分析日志后发现,sql绑定变量达到了了79010个,而oracle是不允许超过65535个的。
解决方案
前面的分析确定了导致oracle挂掉的原因是绑定变量超过了65535个,那对症下药,解决的方案有3个:
业务系统方案
1.循环单条执行merge语句,优点是修改简单,缺点是业务系统跟数据库交互太多,会影响跑批任务执行效率。
2.对mergeFromTableB进行分批调用,比如每1000条调用一次merge方法,改造稍微多一点,但是交互会少很多。
DBA方案
给oracle打一个补丁,这个方案需要停服务。
业务方案2明细有优势,我用这个方案进行了改造,每次1000条,批量merge,代码如下:
for (int i = 0; i < list.size(); i += 1000) {
if (i + 1000 < list.size()) {
tableAMapper.mergeFromTableB(list.subList(i, i + 1000));
} else {
tableAMapper.mergeFromTableB(list.subList(i, list.size()));
}
}
新的问题
按照上面的方案改造完成后,数据库不会奔溃了,但是新的问题出现了。测试的同学发现,每次处理超过1000条数据,非常耗时,有时竟然达到了4分钟,惊呆。
看打印的批量sql,类似于下面的语句:
begin
merge into table_a ta USING(...;
merge into table_a ta USING(...;
end;
分析了一下,虽然放在了一个SQL块中,但还是单条执行,最后一起提交。
再做一次优化,把上面多条merge语句合成1条。
我的优化思路是创建一张临时表,先把list中的数据插入到临时表中,然后用一次merge把临时表的数据merge进table_a这张表。
oracle的临时表有2种,一种是会话级别,一种是事务级别:
会话级别的临时表,数据会在整个会话的生命周期中,会话结束,临时表数据清空;
事务级别的临时表,数据会在真个事务执行过程中,事务结束,临时表数据清空。
下面看具体实施过程。
1.我们创建一张会话临时表,SQL如下:
create global temporary table_a_temp on commit delete rows as select * from table_a;
comment on table_a_temp is 'table_a表临时表';
2.把table_b查询到的数据list插入临时表,需要在 TableAMapper.xml 增加一个方法:
insert all
into table_a_temp
a,
b,
c,
d,
#{item.a},
#{item.b,jdbcType=VARCHAR},
#{item.c,jdbcType=VARCHAR},
#{item.d,jdbcType=VARCHAR},
select 1 from dual
注意:oracle的insert all语句单次插入不能超过1000条。
3.把临时表的数据merge到table_a中,需要在 TableAMapper.xml 增加一个方法:
MERGE INTO table_a ta
USING (select * from table_a_temp) tb
on (ta.a = tb.a)
WHEN MATCHED THEN UPDATE set
ta.b = tb.b,
ta.c = tb.c,
ta.d = tb.d
WHEN NOT MATCHED THEN
insert
(a, b, c, d)
values
(tb.a, tb.b, tb.c, tb.d)
4.最终业务代码修改如下:
//从table_b查询
List list = tableBMapper.selectForPage(startPage, 10000);
//批量插入table_a_temp临时表
for (int i = 0; i < list.size(); i += 1000) {
if (i + 1000 < list.size()) {
tableAMapper.batchInsertTemp(list.subList(i, i + 1000));
} else {
tableAMapper.batchInsertTemp(list.subList(i, list.size()));
}
}
//从table_a_temp把数据merge到table_a
tableAMapper.mergeFromTempData();
总结
在oracle上执行SQL时,如果绑定变量的数量超过了65535,会引发ORA-07445。当然,引发ORA-07445的原因还有其他。
解决这个问题最好的方式是从业务代码层面进行修改。
也可以让DBA可以给oracle打一个补丁,但是oracle必须要停服务。
oracle挂证多少钱一个月_惊呆,一条sql竟然把Oracle搞挂了相关推荐
- 亚马逊的vps多少钱一个月_如何查看您在亚马逊上花了多少钱
亚马逊的vps多少钱一个月 Have you ever wondered how much you've spent at Amazon during your lifetime? Whether y ...
- 更改ip地址的软件多少钱一个月_武汉社保代缴多少钱一个月?武汉社保一个月交多少钱?...
对于相当一部分职场人群而言,有了社保代缴的参保方式更加可以保障自己的社保账户连续性.但是在代缴的过程中,大家往往问题很多,想了解代缴的参保形式.了解多少钱.了解代缴后的重新入职问题,结合此前网友的提问 ...
- 惊呆,一条sql竟然让oracle奔溃了
一条sql就能让oracle挂了,真的是不敢相信啊,前几天生产上确实出现了这样一个故障,我们来一起做一个事件回放. 系统介绍 系统架构见下图: application1和application2是一个 ...
- 萍乡电子工程师多少钱一个月_电子工程师月薪是多少?工资待遇及前景怎么样...
原标题:电子工程师月薪是多少?工资待遇及前景怎么样 又到一年一度的毕业季,很多大学生都开始忙着找工作了.还有很多同学不太了解电子工程师月薪是多少?工资待遇及前景怎么样?下面有途网小编就详细和同学说说. ...
- 萍乡电子工程师多少钱一个月_电子工程师工资是多少
电子工程师 电子工程师指从事电子设备和信息系统研究.教学.产品设计.科技开发.生产和管理等工作的高级工程技术人才.电子工程师一般分为硬件工程师和软件工程师.硬件与软件是不可分离的,硬件需要软件来执行其 ...
- 网页设计工资一般多少_理发师工资一般多少钱一个月
现在社会物价上涨,就连理发的价格也上涨了,但是虽然价格上涨了,质量却未必保证了.理发师在现在生活中可是少不了的,尤其是对女性朋友来说,发型设计可是至关重要的,因此虽然理发的价格上涨,但是依旧阻止不了女 ...
- 程序员工资一般多少钱一个月?【推荐】
其他行业没这么麻烦,一个职位总是有很多人能胜任的,选择多了,公司就有条件把工资降低.但在程序员招聘方面,谈工资的权利在程序员手里,因为对方没有选择.程序员本来就那么稀有,非常适合要求的程序员更是稀有之 ...
- 迅雷超级会员和白金会员怎么买最便宜多少钱一年多少钱一个月
很多同学因为下载资讯需要开通迅雷超级会员或白金会员,但是不知道怎么购买最便宜,也不知道多少钱一年,多少钱一个月购买比较划算.下面就和大家分享迅雷会员怎么买最便宜划算. 迅雷是一款非常不错的下载软件,我 ...
- web前端工资一般多少?在北京前端工程师多少钱一个月?
前端工程师工资多少钱一个月?好程序员告诉大家:平均月薪20K以上,大厂年薪30万起步.web前端工程师在北上广深有巨大的就业需求,所以很多小伙伴选择了学习前端.那么web前端工程师工资一般多少钱呢? ...
最新文章
- oracle存储过程的常用语法
- 第十七届全国大学生智能车竞赛完全模型组 I 型车模数据
- Linux下的静态库、动态库和动态加载库
- 我现在的简历以及后面的更改方向
- 【归并排序】奶牛的图片(jzoj 1812)
- TrueCommand是什么
- 1.8 centos7网络排错
- Oracle数据导入导出imp/exp sp2-0734:未知的命令开头'imp...解决方法
- 使用curl与wget发送get与post请求
- Linux下载Java包,Linux环境Java包的安装和环境配置
- 全国大学生数学竞赛学习笔记
- c++编译时出现discards qualifiers [-fpermissive]的错误
- unity PC 、安卓修改数据库文件
- Word查找和替换通配符(完全版)
- 一款游戏让你成为 Vim 高手!
- JBPM4.4业务流程管理框架详细解读
- 夜光 :AGV 导航策略总体方案设计
- 典型相关分析(Canonical Correlation Analysis, CCA)
- windows 键盘记录器(win10下测试成功)
- java分布式事务——seata,tcc解决方案总结!
热门文章
- 从ASP.NET Core2.2到3.0你可能会遇到这些问题
- 使用.NET Core与Google Optimization Tools实现加工车间任务规划
- FinTech浪潮已到,五大金融场景将迎变革
- 帅呆了!微软即将发布 Visual Studio for Mac 预览版
- .NET Core性能测试组件BenchmarkDotNet 支持.NET Framework Mono
- 理解 .NET Platform Standard
- 在Linux以及Mac OS X启用F#
- 云计算产值将超3000亿美元 亚马逊微软谷歌居三甲
- 我的未来计算机作文,我的未来作文(精选4篇)
- jQuery选择器和选取方法