oracle单表数据量上亿_大数据量面前,毫秒必争。一次上亿数据量程序优化后的感想...
最近在搞一个开发一个程序,数据量很大,预计大概有上亿的数据量。程序中需要依次遍历原始数据,然后根据原始数据进行数据计算以及数据整合。 一开始项目组接到这个任务以后,一直在犹豫,生产服务器是否可以跑得动,毕竟在开发环境很难实现像生产环境那样的数据量以及服务器配置。项目组一直在论证,是否可以实现此功能,万一上线以后跑不动,或者需要跑好长时间,根本就没有办法交代。 最终项目组决定还是试试看。 首先,我.
最近在搞一个开发一个程序,数据量很大,预计大概有上亿的数据量。程序中需要依次遍历原始数据,然后根据原始数据进行数据计算以及数据整合。
一开始项目组接到这个任务以后,一直在犹豫,生产服务器是否可以跑得动,毕竟在开发环境很难实现像生产环境那样的数据量以及服务器配置。项目组一直在论证,是否可以实现此功能,万一上线以后跑不动,或者需要跑好长时间,根本就没有办法交代。
最终项目组决定还是试试看。
首先,我们找到了一台2C4G的数据库服务器以及应用服务器,生产环境数据库是16C64G,应用服务器是4C8G。在测试环境大概造了1000万的数据量,以此数据量作为开发测试目标,于生产服务器的上亿数据量作为对标。采用多线程的方式完成。
第一次开发完成后,程序根本跑不动,应用服务器屡屡的内存溢出。不停的报java.lang.OutOfMemoryError: PermGen space。通过查询发现,mysql在执行查询操作时候,会把结果集数据首先拉到本地服务器,如此大的数据量,内存不挂才怪。所以,赶紧修改程序。
p = conn.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
p.setFetchSize(Integer.MIN_VALUE);
p.setFetchDirection(ResultSet.FETCH_REVERSE);
修改完成后,内存溢出的问题已经解决了,但是发现在执行p.executeBatch()的时候特别的慢,慢到令人发指,不可思议。后来调整了mysql jdbc连接参数,在连接参数中添加了
rewriteBatchedStatement=true
参数,开启了批量出来,原来不添加的话,jdbc还是一条一条向服务器提交。
再次发动执行,发现虽然p.executeBatch()执行速度快了,但是还是不是让人特别满意,所以又修改了sql程序拼接方法,优化insert执行语句,由原来的
insert into tables (name1,name2,...) values (?,?,....)
insert into tables (name1,name2,...) values (?,?,....)
insert into tables (name1,name2,...) values (?,?,....)
修改为
insert into tables (name1,name2,...) values (?,?,....),(?,?,....),(?,?,....),(?,?,....)
效率提升了很多。
程序处理过程中,需要有update操作,如果数据存在,需要update,之前的设计是先按照主键查询,如数据存在,则update,不存在则执行insert操作。但是效率还是不满意。所以再次修改程序,在insert语句后添加了ON DUPLICATE KEY UPDATE参数。
insert into tables (name1,name2,...) values (?,?,....),(?,?,....),(?,?,....),(?,?,....) ON DUPLICATE KEY UPDATE name1=values(name1)......
修改后,程序不用再执行先查询后判断是否需要更新等等。
程序修改到这里,其实就可以顺利完成了,1000万的数据在测试服务器6个并发的时候需要140分钟,程序每分钟可以处理7.1万笔数据。
但是,我一直在思考,是否可以再快一些,而且我发现,6个并发同时执行时,应用服务器的CPU飚的非常高,每次都可以到95%以上,而数据库服务器其实并不是非常的繁忙。这个不正常,按说数据库服务器应该很忙才对,所以可能还是有优化的地方。
出于探索的精神,项目组再次启程,首先就从CPU下手。
通过阿里巴巴的arthas工具,我们成功的开始监控某个线程操作,每隔10秒钟抓一次线程正在执行的内容,我们惊奇的发现,大部分的时候,线程都在执行同一个操作,就是Spring EL表达式解析、计算工作。
为了方便程序开发和配置,我们此采用了配置文件配置的方式,对于一些计算项,采用Spring EL表达式配置,方便项目组调试、调整。难道真的是EL表达式拖了后腿?
我们首先把所有的EL表达式都去掉,改用默认值的方式测试了一次,当程序启动时候,日志的刷新速度让我们目不暇接,20分钟就完成了批量。项目组顿时兴奋不已,就是它拖了后腿。
通过前后计算,我们处理每条数据执行了5个EL表达式,1000万行数据就是5000万次,平均计算了下,每个EL表达式需要执行7毫秒,其实也不长看起来,但是乘以5000万,那就是120分钟。
然后,项目组立即决定取消EL表达式配置的模式,采用java程序计算的方式完成需要计算的业务数据来完成,虽然可能损失了灵活配置,但是提交了执行效率,这笔账划得来。
修改后,程序在22分钟就执行完成,每分钟完成45.5万笔数据,CPU峰值降到了60%。
7毫秒,看起来真的不多,但是架不住几千万上亿次的调用。
这次调优让项目组变得很兴奋,现在项目组成员在日常开发过程中,已经养成了非常好的调优的好习惯,运行稍微有点慢或者不满意,就不停的查找、定位、解决,我仿佛已经可以看到一批高级的人才已经在冉冉升起了。因为调优真的很复杂,涉及到网络、IO、应用程序设计、逻辑梳理、数据库等等各方各面,只有不断的追求、学习才能用的好,用的精。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)