最近做了一个系统,是从各个地方按照不同的接口同步订单,底层采用的是Spring JdbcTempalte,支持按预订时间分表存储和查询的功能,使用到了jdbc的BatchUpdate功能.生产环境采用的是AWS,使用的数据库方案是AWS的RDS(Rational DataBase Service),这是我第一次使用RDS.本地环境测试起来一切正常,但是发布到生产环境CPU就飙到100%,且一条直线横到底.
虽然RDS的服务不会挂,但是系统的性能受到严重的影响.第一次使用AWS的RDS数据库,我简答的认为Amazon Aurora与常用的mysql是一样的,后来查询RDS的文档,才发现有一些不同.
Amazon Aurora 是一个兼容 MySQL 的关系数据库引擎,结合了高端商用数据库的速度和可用性以及开源数据库的简单性和成本效益。Amazon Aurora 的性能最高可达到 MySQL 的五倍,并且能以十分之一的成本提供商用数据库的安全性、可用性和可靠性。
这是http://aws.amazon.com/cn/rds/aurora/上对Aurora的介绍,一直把所有的文档看完,但是还是没有能解决我的问题,通过查询的ShowProcessList和程序的日志上来看,发现系统在执行一些Sql方面有严重的性能问题.
比如根据订单号删除订单的同步任务.
delete from res_id_list_for_fetch where ersp='XXX' And source='yyyy'
这条语句居然会死锁,执行SQL时,如果指定了主键,那么速度是最快的,主键是唯一的,所以只需锁定这一行记录即可,但是上面的SQL里面,是有3kw的数据量的基础上执行的,而且没有索引,所以直接锁定了整个表,在40个线程并发执行的情况下,出现死锁就不足为奇了.所以解决方案也是很简单,对ersp和source建立索引.
同时,在执行BatchUpdate时,slowlog的日志也显示有性能问题,在stackoverflow 上看到有位仁兄也遇到过这样的问题
http://stackoverflow.com/questions/2993251/jdbc-batch-insert-performance
根据上面的解决方案,在jdbc的url上加入参数
?useServerPrepStmts=false&rewriteBatchedStatements=true"
默认的情况下,rewriteBatchedStatements是false,这个参数的设置的解释如下
I'd like to expand on Bertil's answer, as I've been experimenting with the connection URL parameters.
rewriteBatchedStatements=true
is the important parameter.useServerPrepStmts
is already false by default, and even changing it to true doesn't make much difference in terms of batch insert performance.Now I think is the time to write how
rewriteBatchedStatements=true
improves the performance so dramatically. It does so byrewriting of prepared statements for INSERT into multi-value inserts when executeBatch()
(). That means that instead of sending the followingn
INSERT statements to the mysql server each timeexecuteBatch()
is called :INSERT INTO X VALUES (A1,B1,C1)INSERT INTO X VALUES (A2,B2,C2)...INSERT INTO X VALUES (An,Bn,Cn)It would send a single INSERT statement :
INSERT INTO X VALUES (A1,B1,C1),(A2,B2,C2),...,(An,Bn,Cn)You can observe it by toggling on the mysql logging (by
SET global general_log = 1
) which would log into a file each statement sent to the mysql server.
按照以上的解决方案,该建立索引的建立索引,连接参数也修改了,部署到生产环境,后来观察,cup一直稳定在3%.问题得到解决.
总结 对于经常使用的查询字段,该建立索引的还是要建立索性,血的教训.