EF6 + SQL 14:将大量行上传到表中的最有效方法

Posted

技术标签:

【中文标题】EF6 + SQL 14:将大量行上传到表中的最有效方法【英文标题】:EF6 + SQL 14: The most effective way to upload large number of rows into a table 【发布时间】:2016-07-25 15:30:46 【问题描述】:

使用 Entity Framework 6 和 SQL Server 2014:

我需要将 XML 文件中的大约 200,000 行上传到 SQL Server 表中。每行有 5 个字段。一行的数据不大,但是我的行数很多。

在你的 C# 应用程序中,我可以解析 XML 文件并在内存中读取它的数据没有问题。但我担心每行向 SQL Server 发送一个 TSQL 存储过程调用效率不高。在 EF6 中实现此要求的最有效方法是什么?

如果Entity Framework不适合这个,我可以直接使用ADO.NET。

【问题讨论】:

如果您需要做的事情包括大量的清理和转换,请考虑在 SSIS 中进行。 @HLGEM,将 SSIS 许可成本和部署添加到一个文件的体系结构会有点过度设计。 【参考方案1】:

您可以将多行打包到一个 DataTable 中,并作为表值参数 (tvp) 传递给您的存储过程。您的存储过程可以使用 tvp 作为源执行 MERGE 语句,或者连接到 tvp 的 INSERT 语句。

这在使用直接 ADO.NET 时效果很好。从一个快速的谷歌来看,它看起来也应该通过实体框架工作。例如:http://www.c-sharpcorner.com/UploadFile/78607b/using-table-valued-parameters-in-entity-framework

一些tvps相关的链接:

http://www.sommarskog.se/arrays-in-sql-2008.html

http://www.sommarskog.se/arrays-in-sql-perftest-2009.html

【讨论】:

这太棒了。非常感谢!是否有任何指导方针可以有多大的 TVP?我正在考虑将数据分成块,但我需要知道 TVP 的最佳大小是多少? 我对 TVP 的大小没有任何限制,但我想如果它们太大,您最终可能会遇到操作系统强加的内存限制。将其分成块是一个好主意 - 它还可能有助于减少 MERGE 或 INSERT 期间 SQL Server 锁定的数量。我通常使块大小可配置,以便在代码实现和试用后轻松调整。如果 tvp 只有一个 guid 主键,我会将块大小默认为 5000 或类似的值,但显然涉及很多因素。【参考方案2】:

尝试使用OPENROWSET直接解析:

DECLARE @xml XML
SELECT @xml = BulkColumn
FROM OPENROWSET(BULK 'D:\sample.xml', SINGLE_BLOB) x

SELECT t.c.value('.', 'NVARCHAR(100)')
FROM @xml.nodes('root/row') t(c)
GO

【讨论】:

SQL Server 机器无权访问 \\UNC\Share\File.xml。 OPENROWSER 能否在 SqlClinet 机器上打开文件并发送到 SQL 服务器?【参考方案3】:

您可以通过在添加实体并在调用 SaveChanges 之前再次打开它时设置 context.AutoDetectChangesEnabled = false 来显着提高实体框架的性能。小批量添加实体并每次处理上下文也会有所帮助。

或者有一些第三方库做得更好:

EntityFramework.BulkInsert

Entity Framework Extensions

Entity Framework Plus

后两者是商业的,我相信 Entity Framework Plus 是 Entity Framework Extensions 的演变。

【讨论】:

以上是关于EF6 + SQL 14:将大量行上传到表中的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

SQL 增删改语句

通过 python 将 csv 文件插入 MySQL。运行但数据未填充到表中

(Golang)将数组中的所有行插入到表中

第二种形式的数据是如何发送到表中的?

如何将具有多个值的列加载到表中的单独行中

如何使用 VBA 将“整个”DAO 记录集插入到表中