EF MYSQL批量更新_一次EF批量插入多表数据的性能优化经历

一次EF批量插入多表数据的性能优化经历

來源:互聯網  2016-05-20 19:24:00  評論

一次EF批量插入多表数据的性能优化经历 距离上次的博客已经有15个多月了,感慨有些事情还是需要坚持,一旦停下来很有可能就会停很久或者从此再也不会坚持。但我个人一直还坚持认为属于技术狂热份子,且喜欢精益求精的那种。最近遇到两个和数据迁移相关的项目,均遇到需要性能优化的问题,这里拿第二个项目的一个小优化过程与大家分享,技术并不高深,我注重的是解决问题的过程。我的方案是有业务背景以及技术背景限制的,不一定适合其它项目,优化是相对的。

业务场景:我们需要迁移一批老的合同订单数据,其有一个合同的订单数为519条,迁移到新表中会涉及到主要的4个表,就是说519条老数据,会变成519*4。 技术背景:数据库是MySQL,后台采用的是微软的EF

问题:迁移这批订单当时最好的性能方案是14秒(未优化前是分钟级别),我们总共有400000订单,算下最理想状态下的总时间:=(14/519)*400000/3600=3小时,再算下取数据,转换数据的时间,基本要4小时。如果中途有异常,这个时间可能需要一夜甚至更长的时间才能迁移完,这真正恶梦。 先来看看优化前:优化前导519个合同是分钟级别的,看下代码后我的方案是分三步:

1:按批次,比如10个合同一批来操作,将后续需要的数据全部取出来。原方案是用到哪查到哪,试想400000的订单还不查个一天两天的。 2:转换数据,将源数据转换成新的对象集合,此处不操作数据库。 3:批量插入数据,将转换后校验无误的数据导入数据库,原方案是逻辑到哪,哪就插入数据库。不便于定位性能瓶颈也不方便进行有针对性的优化。 根据以上三个步骤,我们就很容易精确定位是哪方面慢了,是查询数据库慢,转换数据慢,还是插入数据库慢。 经过此方面调整后的结果: 1:一次性读取数据后,性能明显提升,降低了数据库读取次数,享受到了批量取数据的好处; 2:定位到性能瓶颈在于数据库插入,总时间15秒,保存数据花了14秒

疑惑:我对保存519*4条数据需要14秒的结果不满意,我坚定认为数据库插入如此小数量级的数量不需要这么长的时间。再次分析,发现我们需要保存多张表的数据,且相互之间存在依赖关系,即第二张表的数据需要第一张表插入后的主键,这样我们在写EF时,会出现多条SaveChange的方法。519个订单做循环,SaveChange的总次数:519*3。 改造:分三次数据库操作 1:先全量保存第一个被依赖的表,此时由于EF的数据追踪功能,插入数据库后,对象上会自动赋值主键信息; 2:再全量保存第二个被依赖的表,由于被依赖的表在第一步已经更新成功,此处能够成功获取到外键; 3:最后全量保存第三被依赖的表。

此方案的SaveChange次数降低到3次,执行时间变更5.5秒,性能提高接近200%。 数据库事务,如果我们的操作加上事务会怎样?我们从优化前的版本开始看(不是上面提到的分打开三次数据库批量操作):主要利用TransactionScope来完成

using (var trans = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { Timeout = new TimeSpan(0, 0, 240), IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead }))

1:519*3次SaveChange,最外层嵌套一个大事务,不嵌套是58秒,嵌套了50秒,两者相关不大,如果是一个DbContext出现大量的SaveChange,有事务从结果来看性能更优化,具体原因不明,待调查。 2:519*3次SaveChange,缩小事务范围,将事务放在循环体内部,结果变成14秒,看来小事务还是值得推荐的。 再看改造后的分三次数据库操作每次一次SaveChange的场景:外面嵌套一个大事务,嵌套是5.5秒,不嵌套是5.8,相差不大。

单一职责,上面的批量插入数据库使用了三次打开数据库,每次只有一个SaveChange,那么在一个DbContext中操作调用三次SaveChange呢? 在一个DbContext中做三次SaveChange是32秒,采用三个DbContext分开操作是5.5秒,结论是大批量数据插入,避免在同一DbContext中做多次SaveChange。

结论:

1:避免使用大的数据库事务,尽量控制在有需求时打开,不需要时及时关闭,它会锁定资源的;

2:批量插入表数据,尽量避免在同一DbContext下做多次SaveChange操作;

3:如果有大批数据需要插入表,尽量采用单表集中插入后再操作后续表,避免插入一条数据SaveChange一次;

4:读取数据尽量按批量读取,避免取一条数据读取一次:查询100次单条记录与一次性查询100条记录是有很大差距的。

一次EF批量插入多表数据的性能优化经历 距离上次的博客已经有15个多月了,感慨有些事情还是需要坚持,一旦停下来很有可能就会停很久或者从此再也不会坚持。但我个人一直还坚持认为属于技术狂热份子,且喜欢精益求精的那种。最近遇到两个和数据迁移相关的项目,均遇到需要性能优化的问题,这里拿第二个项目的一个小优化过程与大家分享,技术并不高深,我注重的是解决问题的过程。我的方案是有业务背景以及技术背景限制的,不一定适合其它项目,优化是相对的。

业务场景:我们需要迁移一批老的合同订单数据,其有一个合同的订单数为519条,迁移到新表中会涉及到主要的4个表,就是说519条老数据,会变成519*4。 技术背景:数据库是MySQL,后台采用的是微软的EF

问题:迁移这批订单当时最好的性能方案是14秒(未优化前是分钟级别),我们总共有400000订单,算下最理想状态下的总时间:=(14/519)*400000/3600=3小时,再算下取数据,转换数据的时间,基本要4小时。如果中途有异常,这个时间可能需要一夜甚至更长的时间才能迁移完,这真正恶梦。 先来看看优化前:优化前导519个合同是分钟级别的,看下代码后我的方案是分三步:

1:按批次,比如10个合同一批来操作,将后续需要的数据全部取出来。原方案是用到哪查到哪,试想400000的订单还不查个一天两天的。 2:转换数据,将源数据转换成新的对象集合,此处不操作数据库。 3:批量插入数据,将转换后校验无误的数据导入数据库,原方案是逻辑到哪,哪就插入数据库。不便于定位性能瓶颈也不方便进行有针对性的优化。 根据以上三个步骤,我们就很容易精确定位是哪方面慢了,是查询数据库慢,转换数据慢,还是插入数据库慢。 经过此方面调整后的结果: 1:一次性读取数据后,性能明显提升,降低了数据库读取次数,享受到了批量取数据的好处; 2:定位到性能瓶颈在于数据库插入,总时间15秒,保存数据花了14秒

疑惑:我对保存519*4条数据需要14秒的结果不满意,我坚定认为数据库插入如此小数量级的数量不需要这么长的时间。再次分析,发现我们需要保存多张表的数据,且相互之间存在依赖关系,即第二张表的数据需要第一张表插入后的主键,这样我们在写EF时,会出现多条SaveChange的方法。519个订单做循环,SaveChange的总次数:519*3。 改造:分三次数据库操作 1:先全量保存第一个被依赖的表,此时由于EF的数据追踪功能,插入数据库后,对象上会自动赋值主键信息; 2:再全量保存第二个被依赖的表,由于被依赖的表在第一步已经更新成功,此处能够成功获取到外键; 3:最后全量保存第三被依赖的表。

此方案的SaveChange次数降低到3次,执行时间变更5.5秒,性能提高接近200%。 数据库事务,如果我们的操作加上事务会怎样?我们从优化前的版本开始看(不是上面提到的分打开三次数据库批量操作):主要利用TransactionScope来完成

using (var trans = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { Timeout = new TimeSpan(0, 0, 240), IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead }))

1:519*3次SaveChange,最外层嵌套一个大事务,不嵌套是58秒,嵌套了50秒,两者相关不大,如果是一个DbContext出现大量的SaveChange,有事务从结果来看性能更优化,具体原因不明,待调查。 2:519*3次SaveChange,缩小事务范围,将事务放在循环体内部,结果变成14秒,看来小事务还是值得推荐的。 再看改造后的分三次数据库操作每次一次SaveChange的场景:外面嵌套一个大事务,嵌套是5.5秒,不嵌套是5.8,相差不大。

单一职责,上面的批量插入数据库使用了三次打开数据库,每次只有一个SaveChange,那么在一个DbContext中操作调用三次SaveChange呢? 在一个DbContext中做三次SaveChange是32秒,采用三个DbContext分开操作是5.5秒,结论是大批量数据插入,避免在同一DbContext中做多次SaveChange。

结论:

1:避免使用大的数据库事务,尽量控制在有需求时打开,不需要时及时关闭,它会锁定资源的;

2:批量插入表数据,尽量避免在同一DbContext下做多次SaveChange操作;

3:如果有大批数据需要插入表,尽量采用单表集中插入后再操作后续表,避免插入一条数据SaveChange一次;

4:读取数据尽量按批量读取,避免取一条数据读取一次:查询100次单条记录与一次性查询100条记录是有很大差距的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值