13

我正在构建一个通过各种 CSV 提要更新大量数据的系统。通常我会遍历提要中的每一行,执行选择查询以检查项目是否已经存在,并根据项目是否存在插入/更新项目。

我觉得这种方法的可扩展性不是很高,并且可能会在较大的提要上锤击服务器。我的解决方案是像往常一样循环遍历这些项目,但将它们存储在内存中。然后,对于每 100 个左右的项目,对这 100 个项目进行选择,并获取数据库中匹配的现有项目的列表。然后将插入/更新语句连接在一起并将它们运行到数据库中。这基本上会减少访问数据库的次数。

这是一个足够可扩展的解决方案吗?是否有任何关于将大型 Feed 导入生产环境的示例教程?

谢谢

4

5 回答 5

14

看到您使用的是 SQL Server 2008,我会推荐这种方法:

  • 首先将您的 CSV 文件批量复制到临时表中
  • 使用 MERGE 命令从该临时表更新您的目标表

查看MSDN 文档和一篇关于如何使用 MERGE 命令的精彩博客文章。

基本上,你在你的实际数据表和暂存表之间建立一个共同标准(例如一个共同的主键)的链接,然后你可以定义什么时候做什么

  • 行匹配,例如该行同时存在于源表和目标表中——>通常你要么更新一些字段,要么一起忽略它
  • 源中的行在目标中不存在 --> 通常是 INSERT 的情况

你会有这样的MERGE声明:

MERGE TargetTable AS t
USING SourceTable AS src
ON t.PrimaryKey = src.PrimaryKey

WHEN NOT MATCHED THEN
  INSERT (list OF fields)
  VALUES (list OF values)

WHEN MATCHED THEN
  UPDATE
    SET (list OF SET statements)
;

当然,ON如果需要,该子句可以涉及更多。当然,您的WHEN陈述也可以更复杂,例如

WHEN MATCHED AND (some other condition) THEN ......

等等。

MERGE是 SQL Server 2008 中一个非常强大且非常有用的新命令 - 如果可以,请使用它!

于 2010-02-26T14:46:35.613 回答
3

你的方式是最糟糕的解决方案。一般来说,您不应该考虑单独循环遍历记录。我们曾经有一个公司构建的循环记录导入工具,加载一个包含超过一百万条记录的文件需要 18-20 个小时(这在构建时并不常见,但这是很多次现在发生的一天)。

我看到两个选项:首先使用批量插入加载到临时表并在该表上执行您需要执行的任何清理操作。你如何确定记录是否已经存在?您应该能够通过在确定更新的那些字段上加入临时表来构建基于集合的更新。通常我会在我的暂存表中添加一列,以获取它匹配的记录的 id,并通过查询填充该列,然后完成更新。然后您插入没有相应 id 的记录。如果您有太多的记录要一次完成,您可能希望分批运行(是的,这是一个循环),但是一次使批次远大于 1 条记录(我通常从 2000 开始,然后基于确定我是否可以在批次中做更多或更少所需的时间)。

我认为 2008 也有一个合并语句,但我还没有机会使用它。在网上的书里查。

另一种方法是使用针对速度进行了优化的 SSIS。SSIS 是一件复杂的事情,而且学习曲线很陡峭。

于 2010-02-26T14:36:10.020 回答
2

一种方法是将您的 CSV 加载到 DataTable(或更可能是 DataReader)中,然后使用 SqlBulkCopy 在结果中批量猛击 -

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

它非常有效,您可以进行一些列映射。提示 - 当您使用 SqlBulkCopy 映射列时,它们区分大小写。

于 2010-02-26T13:48:38.843 回答
0

另一种方法是在服务器上的服务器上编写一个 .Net 存储过程来对整个文件进行操作......

不过,只有当您需要比 Kris Krause 的解决方案更多的控制权时 - 我非常喜欢在我们可以做到的地方保持简单(和可重用)......

于 2010-02-26T13:56:05.780 回答
0

你需要自己在这里滚动吗?是否有可能以 SQL Server 可以使用批量导入加载数据的方式提供数据,然后在导入完成后处理数据库中的重复项?

当涉及到大量数据的繁重工作时,我的经验往往是尽可能多地在数据库中工作会更快且资源密集度更低。

于 2010-02-26T14:07:03.763 回答