【问题标题】:Decrease processing time in parsing large xml file in php减少在 php 中解析大型 xml 文件的处理时间
【发布时间】:2012-08-12 14:33:17
【问题描述】:

就大型 xml 文件的处理时间而言,我遇到了这个问题。大,我的意思是平均600MB。 目前,解析数据并将其插入数据库大约需要 50 - 60 分钟。 我想请教如何改进处理时间的建议?大概需要 20 分钟。

因为按照当前时间,我需要 2.5 个月才能用 xml 中的内容填充数据库。顺便说一句,我有 3000 多个 xml 文件,平均为 600mb。还有我的 php 脚本在命令行中通过 cron 作业。

我还阅读了类似下面的其他问题,但我还没有找到任何想法。 What is the fastest XML parser in PHP?

我看到有些解析的文件最大为 2GB。我想知道处理时间有多长。

希望各位大神帮忙。 将不胜感激。 谢谢。

我有这个代码:

$handler = $this;
$parser = xml_parser_create('UTF-8');
xml_set_object($parser, $handler);
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "cdata");

$fp = fopen($xmlfile, 'r');

while (!feof($fp)) {
    while (($data = fread($fp, 71680))){

    }
}

我首先将解析数据放在一个临时数组中。 我的 mysql 插入命令在 endElement 函数内。 有一个特定的结束标记来触发我对数据库的插入命令。

感谢您的回复....

【问题讨论】:

  • 你当前的密码是多少?!不知道很难提出改进建议。
  • 好的,这是一个没有经验的人的建议:“你试过正则表达式吗?”我想知道正则表达式是否最适合这项任务,抛开编码的简单性。有专家吗?
  • @EzequielMuns Heyyy,你总是可以正则表达式干净,严格格式化的 xml!这就是第二个*答案在那里所说的。正确的? 800+ 票?顺便说一句,很好读:)
  • 我认为 reqex 不会工作,因为它是大文件。而且我必须分块来归档或流式传输内容。因为一次性加载到内存会产生内存错误。

标签: php xml performance parsing profiling


【解决方案1】:

我花了最后一天左右的时间来解决同样的问题。我注意到限制插入查询的数量大大减少了处理时间。您可能已经这样做了,但尝试将一批解析后的数据收集到合适的数据结构中(我使用的是简单的数组,但也许更合适的数据结构可以进一步降低成本?)。在 X 个集合的集合上一次性插入数据 (INSERT INTO table_name (field_name) VALUES (set_1, set_2, set_n) )

希望这对任何可能偶然发现此页面的人有所帮助。我还在解决其他瓶颈,如果我发现新的东西,我会在这里发布。

【讨论】:

  • 谢谢。我对重复的批量插入感到担忧。我需要在插入查询之前进行检查。对此有任何想法。我仍然觉得处理时间很长。
  • 比较非常昂贵。他们会进一步减慢你的脚本。我将使用 UNIQUE 索引并通过对右列应用上述约束来处理后端的重复项。通过在执行函数前加上 @ 符号来抑制每个查询插入的错误。示例:@mysqli_query() 这样您的插入可以无缝工作,并且所有重复项都被排除在外,因此不会破坏您的脚本。
【解决方案2】:

您似乎只需要解析和读取数据,而不需要编辑 XML。有了这个想法,我想说使用 SAX 解析器是更简单、更快捷的方法。

SAX 是一种解析 XML 文档的方法,但不能验证它们。好消息是您可以将它与 PHP 4 和 PHP 5 一起使用而无需更改。在 PHP 4 中,SAX 解析已在所有平台上可用,因此无需单独安装。

您基本上定义了一个在找到开始元素时运行的函数,以及在找到结束元素时运行的另一个函数(您也可以将一个用于属性)。然后你可以对解析后的数据做任何你想做的事情。

使用 SAX 解析 XML

<?
function start_element($parser, $element_name, $element_attrs) {
  switch ($element_name) {
    case 'KEYWORDS':
       echo '<h1>Keywords</h1><ul>';
       break;
    case 'KEYWORD':
       echo '<li>';
       break;
  }
}

function end_element($parser, $element_name) {
  switch ($element_name) {
    case 'KEYWORDS':
       echo '</ul>';
       break;
    case 'KEYWORD':
       echo '</li>';
       break;
  }
}


function character_data($parser, $data) {
  echo htmlentities($data);
}

$parser = xml_parser_create();
xml_set_element_handler($parser, 'start_element', 'end_element');
xml_set_character_data_handler($parser, 'character_data');

$fp = fopen('keyword-data.xml', 'r')
    or die ("Cannot open keyword-data.xml!");


while ($data = fread($fp, 4096)) {
  xml_parse($parser, $data, feof($fp)) or
   die(sprintf('XML ERROR: %s at line %d',
        xml_error_string(xml_get_error_code($parser)),
        xml_get_current_line_number($parser)));
}


xml_parser_free($parser);   
?>

资料来源:我致力于解析和处理大量 XML 数据。 编辑:更好的例子

编辑:嗯,显然您已经在使用 Sax Parser。只要您实际上以事件驱动的方式处理文件(没有任何额外的开销),您就应该在该部门中处于最佳状态。我会说你无能为力来提高解析性能。如果您遇到性能问题,我建议您查看您在代码中所做的工作以查找性能瓶颈(尝试使用像 this one 这样的 php 分析器)。如果你在这里发布你的代码,我们可以看看!干杯!

【讨论】:

  • 我觉得我的代码和你的差不多。使用您建议的代码,处理一个 600MB 的文件需要多长时间?顺便说一句,我以为我正在使用 XMLReader。我怎么知道我使用的是 SAX 还是 XMLReader?谢谢。
  • 在 PHP 中,XML Parser (php.net/manual/en/book.xml.php) 是 SAX 的一个实现,它是一个具有过程接口的事件驱动解析器。 XML Reader (php.net/manual/en/book.xmlreader.php) 是一个具有面向对象接口的拉式解析器。您使用的是前者。
【解决方案3】:

在没有看到任何代码的情况下,我首先要建议的是不要 使用 DOM 或 SimpleXMLElement,因为它们会将整个内容加载到内存中。

您需要使用像XMLReader 这样的流解析器。


编辑:

由于您已经在使用流解析器,因此您不会从更改解析器中获得巨大收益(老实说,我不知道 XML Parser 和 XMLReader 之间的速度差异,因为后者使用 libxml,它 可能更好,但可能不值得)。

接下来要看的是你是否在代码中做了一些愚蠢的事情;为此,我们需要更深入地了解您是如何实现这一点的。

您说您将数据放入临时数组并在到达结束标记后调用 MySQL insert。您是否使用准备好的语句?您是否使用事务批量进行多次插入?

不过,解决瓶颈的正确方法是在代码上运行 profiler。我最喜欢的工作工具是xhProf with XHGui。这将告诉您哪些函数正在运行,运行了多少次,它们消耗了多长时间和多少内存(并且可以将它们全部显示在一个漂亮的调用图中,非常有用)。

使用该 GitHub 的自述文件中的说明。这是一个tutorial 和另一个useful tutorial(请记住,最后一个是针对没有我链接到的 XHGui 扩展的分析器)。

【讨论】:

  • 也许可以用代码更新您的帖子并对其进行格式化,以便我们称之为“全部查看”。
猜你喜欢
  • 2015-02-04
  • 2017-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 2017-07-23
相关资源
最近更新 更多