使用C#从CSV导入大量数据到数据库

12

如何以最有效的方式将大量的CSV数据(300万+行)加载到数据库中?

  • 数据需要进行格式化(例如,将姓名列拆分为名字和姓氏等)
  • 需要在尽可能短的时间内高效地完成此操作

我倾向于使用C#应用程序逐行读取、转换和加载数据。如果这不是理想的选择,那么我的其他选择是什么? 我需要使用多线程吗?


时间限制有多严格? - Jake
7个回答

5

你将受到I/O限制,因此多线程并不一定会使它运行得更快。

上次我用C#写了大约十几行代码。在一个线程中,它以硬盘能够读取磁盘的速度运行。我从源文件中逐行读取。

如果你不想自己编写,可以尝试FileHelpers库。你也可以看看Sébastien Lorion's work。他的CSV阅读器是专门处理性能问题的。


是的,C# IO库使用缓冲区设计得非常好。最近我需要在大约一分钟内将一个CSV文件转换为另一个(1.5百万行)。 - call me Steve
1
我也推荐使用FileHelpers。它可以帮助我们避免编写解析器来处理包含逗号的值。如果CSV文件中有任何类似的问题,考虑使用FileHelpers。 - Igby Largeman
我知道在过去,磁盘的寻道时间是一个问题。对于大型图像文件,我们会从一个磁盘读取并写入另一个磁盘,以减少重新定位磁头的次数。 - yamspog

3
您可以使用csvreader快速读取CSV文件。
假设您正在使用SQL Server,您可以使用csvreader的CachedCsvReader将数据读入DataTable中,然后使用SqlBulkCopy将其加载到SQL Server中。

这是我使用的。我喜欢csvreader,它是访问分隔文件的非常方便的方式。 - galford13x

2
我同意你的解决方案。逐行读取文件应该避免一次性将整个文件读入内存所带来的开销,这应该使应用程序运行得更快、更高效,主要需要时间是从文件中读取(相对较快)和解析行。我想提醒你的是,如果CSV文件中有嵌入的换行符,请注意。我不知道特定的CSV格式是否实际上会在数据的引号之间输出换行符,但这可能会混淆此算法,当然。
此外,如果不会在检索生成的键值时产生问题(希望您不需要检索任何生成的键值),我建议在将它们发送到数据库之前对插入语句进行分批处理(在一个字符串中包含多个插入语句)。请记住,SQL Server(如果您正在使用它)每批只能处理2200个参数,请限制批量大小以考虑这一点。我建议使用参数化的TSQL语句执行插入操作。我猜测插入记录比从文件中读取记录花费的时间更长。

1

您没有说明使用的是哪个数据库,但考虑到您提到的语言是C#,我会假设您使用的是SQL Server。

如果数据无法使用BCP导入(如果需要进行大量处理,则似乎不行),那么SSIS很可能是下一个最快的选项。它不是世界上最好的开发平台,但它非常快。肯定比您在任何合理时间范围内编写的任何应用程序都要快。


我和Greg以及JayRiggs在这个问题上持相同观点。跳过C#(除非你正在为SQL Server编写CLR模块)。让SQL去处理吧,它擅长从文件中处理大量数据。如果你还没有听说过的话,那就是它的强项。;) 这将为你节省打开连接等方面的所有麻烦。 - jcolebrand
这不是那种单元测试非常有用的问题。人们过于关注单元测试,忽略了更大的问题。你应该试图测试的是,在给定CSV中已知数据集的情况下,进入数据库的数据是否正确,并且已知的错误情况是否按预期处理(修复、丢弃或失败)。如果按照这种方式进行操作,则无论它如何进入数据库,都不会真正有影响。所以从任何实际的角度来看,我认为SSIS与任何其他东西一样可测试。 - Greg Beech

0

BCP非常快,因此我会使用它来加载数据。对于字符串操作,我会在SQL上使用CLR函数,一旦数据到位。在这种情况下,多线程不会有帮助,只会增加复杂性并降低性能。


我在我的C#代码中遇到了一个问题,我正在尝试处理150万行的平面文件,并将其插入到多个SQL Server表中。我正在使用多线程,但是随着代码运行的时间越长,它变得越来越慢。你有什么解决方法吗? - the smart life

0

0
如果你真的想用 C# 来实现这个功能,可以先创建并填充一个 DataTable,然后清空目标数据库表,并使用 System.Data.SqlClient.SqlBulkCopy.WriteToServer(DataTable dt) 方法将数据写入目标数据库表中。

很不幸,我需要更新现有记录,并且数据将每天加载。 - guazz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接