批量操作可显著提升 Entity Framework 的性能

  • Jonathan Allen
  • 谢丽

2014 年 12 月 11 日

话题:语言 & 开发

当数据库管理员考虑高性能数据加载时,他们会考虑批量操作,这明显是 Entity Framework 不具备的功能。但也不一定就是如此。近日,我们采访了ZZZ 项目的 Jonathan Magnan,谈了他们新提供的功能。

InfoQ:开发人员已经可以告诉 Entity Framework 将批量记录同时上传。那么为什么还需要批量操作呢?

Jonathan Magnan:很简单,为了获得巨大的性能。

想象一下,要求某人给你一本书,一次一页(Entity Framework),而不是给你整本书(批量操作)。一种技术明显比另一种技术更快:批量操作的性能要远远超过 Entity Framework。

ZZZ 项目通过Entity Framework 扩展库提供两种批量操作。与 Entity Framework 的 SaveChanges 方法相比,它们极大地提供了性能。

BulkSaveChanges

第一种方式是我们的主要功能,正如字面上的意思,BulkSaveChanges 方法升级了 SaveChanges 方法。当有成千上万个实体时,它的保存速度预计快 10 到 15 倍。该方法支持各种关联和实体类型(TPC、TPH 和 TPT)。

using (var ctx = new DbContextEntities())
{
	//…对 DbContext 做任何修改…
   ctx.BulkSaveChanges();
}

第二种方式是批量操作方法(BulkDelete、BulkInsert、BulkUpdate 和 BulkMerge)。它们对性能的提升更大,而且允许自定义许多设置,比如使用什么主键?

using (var ctx = new DbContextEntities())
{
	//…对 DbContext 做任何修改…

   // 使用 Entity Framework 设置 
   ctx.BulkUpdate(list);

   // 或者自定义设置 
   ctx.BulkUpdate (list,
operation=>operation.ColumnPrimaryKeyExpression=column=>column.ID);
}

InfoQ:在底层的 SQL 方面,批量操作与普通的 Entity Framework 操作有何不同?

Jonathan:Entity Framework 每保存一条记录就产生一次数据库访问。如果有 1000 个实体要更新,就需要访问数据库 1000 次,每次执行一条更新语句,整个过程可能需要几秒钟。另一方面,使用 Entity Framework 扩展库,一眨眼功夫就能完成。

我们可以像下面这样还原 SQL Server 的标准工作流程:

  • 在 SQL Server 中创建一张临时表;
  • 使用.NET SqlBulkCopy 将数据批量插入临时表;
  • 在临时表和目标表之间执行一条 SQL 语句;
  • 从 SQL Server 删除临时表。

数据库访问次数明显减少。

InfoQ:你们针对 Entity Framework 做过基准测试比较普通操作和批量操作码?

Jonathan:基准测试显示了四舍五入后的数值,因为已经相当明显,批量操作总是一种比做多次操作更快的方式。

Nb.Entities

SaveChanges

BulkSaveChanges

BulkOperations

1,000

1,000ms

90ms

70ms

2,000

2,000ms

150ms

110ms

5,000

5,000ms

350ms

220ms

在记录数以百万计的场景中,批量操作是唯一可行的方案。与 Entity Framework 相比,其性能可以为开发人员节省数小时甚至几天的时间。

Nb. Entities

BulkSaveChanges

BulkOperations

100,000

7s

4.5s

1,000,000

75s

45s

10,000,000

750s

450s

在真实环境的场景中,随着列数、索引、触发器和服务器负载的增加,Entity Framework 与批量操作之间的性能差距甚至更大。

此外,速度不是唯一重要的因素,向 SQL Server 服务器发起成千上万次访问从来都不是一个好的解决方案。即使你的应用程序受此低性能的影响不大,但这可能会影响其它应用程序的性能。

InfoQ:批量操作有什么缺点?比如,要使它有效,有最小行数要求吗?

Jonathan:缺点是需要额外的启动加载。同 Entity Framework 一样,在第一次基于实体及其关系使用它时,需要收集并缓存信息。

甚至于只有一行数据时,它都可以同 Entity Framework 效果一样。它会根据需要保存的行数改变保存策略。

InfoQ:你们计划在 CodePlex 上将 Entity Framework 批量操作贡献给 Entity Framework 主干吗?

Jonathan:很遗憾,不会。SqlBulkCopy 已经创建十年多了,.NET Framework 仍然没有支持批量删除、更新和合并。我们提供了这些方法,我们的网站上有更多的功能。

InfoQ:您对微软将 Entity Framework 移交给.NET 基金会有什么看法?

Jonathan: 我认为,微软此举意义重大,因为开源社区发展很快。作为一名程序员,看看微软项目的演进以及微软的开发人员如何编码总是很有趣的。这使经常使用 Entity Framework 的开发人员可以很简单地分享代码、建议和思路。这是我们希望的一次创新性转变, 一定会对微软和.NET 社区产生积极的影响。

查看英文原文:Dramatically Improve Entity Framework Performance with Bulk Operations


感谢孙镜涛对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

语言 & 开发