一条SQL竟然让Oracle奔溃了
lication1和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的表结构如下:的主键都是字段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,看一下代码:中可以看到oracle报了ORA-07445错误。 分析日志后发现,sql绑定变量达到了了79010个,而oracle是不允许超过65535个的。 解决方案 前面的分析确定了导致oracle挂掉的原因是绑定变量超过了65535个,那对症下药,解决的方案有3个: 业务系统方案 1.循环单条执行merge语句,优点是修改简单,缺点是业务系统跟数据库交互太多,会影响跑批任务执行效率。 2.对mergeFromTableB进行分批调用,比如每1000条调用一次merge方法,改造稍微多一点,但是交互会少很多。 DBA方案 给oracle打一个补丁,这个方案需要停服务。
业务方案2明细有优势,我用这个方案进行了改造,每次1000条,批量merge, (编辑:开发网_开封站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |