【问题标题】:What is the fastest way to load an XML file into MySQL using C#?使用 C# 将 XML 文件加载到 MySQL 的最快方法是什么?
【发布时间】:2010-11-30 04:14:06
【问题描述】:

问题

将大型 (> 1GB) XML 文件转储到 MySQL 数据库的最快方法是什么?

数据

有问题的数据是 StackOverflow Creative Commons Data Dump。

目的

这将在我正在构建的离线 StackOverflow 查看器中使用,因为我希望在无法访问互联网的地方进行一些学习/编码。

我想在项目完成后将其发布给 StackOverflow 的其他成员,供他们自己使用。

问题

最初,我一次从 XML 读取/写入 DB 一条记录。这在我的机器上运行了大约 10 个小时。我现在使用的 hacktastic 代码将 500 条记录扔到一个数组中,然后创建一个插入查询来一次加载所有 500 条记录(例如“INSERT INTO posts VALUES (...), (...), (...) ... ;”)。虽然这更快,但仍需要数小时才能运行。显然这不是最好的方法,所以我希望这个网站上的大佬们知道更好的方法。

约束

  • 我正在使用 C# 作为桌面应用程序(即 WinForms)来构建应用程序。
  • 我使用 MySQL 5.1 作为我的数据库。这意味着像“LOAD XML INFILE filename.xml”这样的特性在这个项目中是不可用的,因为这个特性只在 MySQL 5.4 及更高版本中可用。这个限制主要是因为我希望这个项目对我以外的人有用,我不想强​​迫人们使用 MySQL 的 Beta 版本。
  • 我希望将数据加载内置到我的应用程序中(即没有说明“在运行此应用程序之前使用 'foo' 将转储加载到 MySQL 中。”)。
  • 我使用的是 MySQL 连接器/网络,因此MySql.Data 命名空间中的任何内容都是可以接受的。

感谢您提供的任何指点!


目前的想法

将整个 XML 文件加载到列中,然后使用 XPath 对其进行解析的存储过程

  • 这不起作用,因为文件大小受 max_allowed_pa​​cket 变量的限制,默认设置为 1 MB。这远低于数据转储文件的大小。

【问题讨论】:

  • 为什么选择 MySQL?如果您正在构建离线查看器,那么 SQLite 之类的东西似乎更合适。作为奖励,它会比 MySQL 快得多。
  • 老实说,马克,我误以为 SQLite 是为小型数据库设计的。我刚刚查看了该站点,虽然我确实注意到它不是针对“非常大的数据集”的评论,但我重新阅读了该部分的评论并注意到限制确实有多高。也许我会把它看作一个备用数据库。我已经计划允许使用 MSSQL。

标签: c# mysql xml load-data-infile


【解决方案1】:

这有两个部分:

  • 读取xml文件
  • 写入数据库

对于读取 xml 文件,此链接 http://csharptutorial.blogspot.com/2006/10/reading-xml-fast.html 显示使用流阅读器可以在 2.4 秒内读取 1 MB,对于 1 GB 文件,这将是 2400 秒或 40 分钟(如果我的数学工作这么晚) .

根据我的阅读,将数据导入 MySQL 的最快方法是使用 LOAD DATA。

http://dev.mysql.com/doc/refman/5.1/en/load-data.html

因此,如果您可以读取 xml 数据,请将其写入 LOAD DATA 可以使用的文件,然后运行 ​​LOAD DATA。总时间可能少于您体验的小时数。

【讨论】:

  • 读取 XML 文件实际上比您想象的要快得多。我正在使用XmlReader 来读取文件,我很快检查了读取文件和准备查询需要多长时间。通过仅将 PostTypeId 和 Body(我正在使用的两个字段)读取到字符串中(以确保它们被读取,因为我不确定参数化查询何时提取它们的数据),并注释掉 cmd.ExecuteNonQuery() 语句,过程耗时 1 分 12 秒。瓶颈主要在数据库部分,而不是读取的数据。我会考虑重新创建 LOAD DATA 可读文件,谢谢。
  • 您可以通过首先将 XML 输入拆分为多个 XML 文件以便并行处理它们来进一步提高性能。
  • 嗨 Shiraz,我终于开始尝试您关于创建临时文件和使用 LOAD DATA 处理它们的建议。创建文件用了 2 分 22 秒,将文件加载到数据库中用了 2 分 35 秒。我需要研究许多警告,但我相信这些将通过一些小的调整得到修复。 5 分钟加载 120 万条记录远远超出了我的预期。享受你的赏金,这是应得的!
  • 这些错误正是我想的那样。我错误地认为 Body 字段中没有双引号,因为这会关闭原始文件中的 xml 属性,从而使 xml 无效。我没有考虑的是我使用的 XmlReader 正在解码实体,所以存在双引号,这搞砸了 CSV 文件。我避开了所有的斜线,然后又避开了引号,一切都很好。 3 分 34 秒创建文件,2 分 43 秒加载 MySQL - 总共 6 分 17 秒加载 PostTypeId 和 Body 字段!
【解决方案2】:

好的,我在这里做个白痴,用一个问题来回答你的问题。

为什么要把它放在数据库中?

如果...只是假设...您将 xml 写入本地驱动器上的文件,如果需要,在数据库中写入一些索引信息。这应该比尝试加载数据库要快得多,并且更便携。除此之外,您需要的只是一种搜索方式和一种索引关系引用的方式。搜索应该有很多帮助,并且关系方面应该很容易构建?您甚至可以考虑重写信息,以便每个文件都包含一个帖子,其中包含所有答案和 cmets。

不管怎样,只要我的两美分(这不值一毛钱)。

【讨论】:

【解决方案3】:

我有一些想法可以帮助加快速度...

  1. 查询的大小可能需要调整,通常会有一个点,即大语句在解析时间上花费更多,因此变得更慢。 500 可能是最佳的,但也许不是,您可以稍微调整一下(可能更多,也可能更少)。

  2. 多线程。假设您的系统尚未在处理过程中保持平稳,您可以通过将数据分解成块并让线程处理它们来获得一些收益。同样,找到最佳线程数是一项实验,但很多人使用多核机器并且有空闲的 CPU 周期。

  3. 在数据库前端,确保表尽可能裸露。关闭所有索引并在索引之前加载数据。

【讨论】:

    【解决方案4】:

    SqlBulkCopy ROCKS。我用它把一个 30 分钟的功能变成了 4 秒。但是,这仅适用于 MS SQL Server。

    我可以建议您查看您创建的表的约束吗?如果您删除数据库上的所有键、约束等,数据库将减少您的插入工作和递归工作。

    其次,设置初始大小较大的表,以防止在插入空白数据库时调整大小。

    最后看看有没有 MySQL 的批量复制风格的 API。 SQL Server 基本上将数据格式化,因为它会向下传输到磁盘,SQL Server 将流链接到磁盘并输入数据。然后,它对所有数据执行一次一致性检查,而不是每次插入一次,从而显着提高您的性能。

    你需要 MySQL 吗?如果您使用 Visual Studio 并且您的数据库性能/大小较低,SQL Server 会让您的生活更轻松。

    【讨论】:

    • 我不需要 MySQL;这只是我已经安装的。毕竟,这主要是一个个人/投资组合项目。从未使用过 MSSQL,一旦主要项目完成,它将成为次要功能。到时候我肯定会使用 SqlBulkCopy。 MySQL 最接近的东西似乎是 LOAD DATA 语法的封面。至于索引等,该表是裸露的,因为记录只会添加一次。我会检查您的“大初始尺寸”建议。感谢您的想法。
    【解决方案5】:

    this 有帮助吗?它是一个存储过程,将整个 XML 文件加载到列中,然后使用 XPath 对其进行解析并创建一个表/从那里插入数据。看起来有点疯狂,但它可能会奏效。

    【讨论】:

    • 我试过了,但我遇到了让它正常工作的问题。我认为真正的交易破坏者是 max_allowed_pa​​cket,默认设置为 1 MB。由于它正在读取整个 XML 文件,posts.xml 文件大约 1.2 GB,我认为这是不可用的。
    • 我明白你的意思——看起来 max_allowed_pa​​cket 的最大值是 1 GB,但仍然不够大。是否可以将逻辑分区中的 XML 文档(例如,每个表一个文档)分解为多个 XML 文档,然后再将它们提供给 MySQL?
    • 即使我们将文件与表格一一对应,问题仍然存在。 9 月份数据转储中的 posts.xml 文件为 1.19 GB,因此我必须至少将该文件分开。我也只是不愿意要求潜在用户修改他们的 MySQL 安装以允许 1GB 数据包。我想尽可能保持原样,以免引起问题。例如“给我你的服务器地址和凭据,剩下的交给我……哦,你介意确保所有内容都以 utf8 传输,因为这不像文档说的那样默认吗?谢谢……”
    【解决方案6】:

    不是你想要的答案,但是mysql c api有mysql_stmt_send_long_data函数。

    【讨论】:

      【解决方案7】:

      我在您上面的一个 cmets 中注意到您正在考虑使用 MSSQL,所以我想我会发布这个。 SQL Server 有一个名为 SQML​​XMLBulkLoad 的实用程序,旨在将大量 XML 数据导入 SQL Server 数据库。以下是 SQL Sever 2008 版本的文档:

      http://msdn.microsoft.com/en-us/library/ms171993.aspx

      早期版本的 SQL Server 也有此实用程序

      【讨论】:

      • 这实际上是我问这个问题的部分原因。我对 10 小时的加载时间感到失望,但有点耸耸肩说“嗯,这是很多数据..此外,我以后会有足够的时间来加快速度”但后来我看到了 Meta 上的帖子抱怨 MSSQL 加载时间为 8 分钟,我很生气。这家伙把他的代码放在github上,这就是他正在使用的。嗯,SqlBulkCopy,不是你说的 XML 版本。感谢您提供的信息,当我开始使用其他数据库时,我一定会牢记这一点(这是我的一个玩具项目,用于学习/投资组合目的)。谢谢!
      【解决方案8】:

      在PostgreSQL 中,获取批量数据的绝对最快方法是删除所有索引和触发器,使用 MySQL 的 LOAD DATA 等效项,然后重新创建索引/触发器。我使用这种技术在大约 10 分钟内将 5 GB 的论坛数据提取到 PostgreSQL 数据库中。

      当然,这可能不适用于 MySQL,但值得一试。此外,this SO question's answer 表明这实际上是 MySQL 的可行策略。

      一个快速的谷歌在increasing the performance of MySQL's LOAD DATA上发现了一些提示。

      【讨论】:

        猜你喜欢
        • 2012-12-09
        • 1970-01-01
        • 2011-07-16
        • 1970-01-01
        • 2015-02-11
        • 2019-07-18
        • 2021-02-17
        • 1970-01-01
        • 2011-01-24
        相关资源
        最近更新 更多