代码之家  ›  专栏  ›  技术社区  ›  ftrotter mario

优化php命令行脚本以处理大型平面文件

  •  0
  • ftrotter mario  · 技术社区  · 16 年前

    为落选的仙女们。。我知道php是一种错误的语言。。。但我是在外界的限制下工作的。鉴于:

    我最初尝试在导入平面文件时使用ORM系统。即使小心地释放对象,该设计也存在大量php内存泄漏问题。即使我确保有足够的内存,脚本也需要大约25天才能在我的桌面上运行。

    我去掉了开销并重写了脚本以直接构建mysql命令。我从设计中删除了AUTO INCREMENT,因为这要求我将最后输入的id作为Mysql,以便在数据点之间建立关系。我只是对数据库ID使用一个全局计数器,我从不做任何查找,只是插入。

    使用这些优化(希望它们能帮助其他人),我让导入脚本在大约6小时内运行。

    我租了一个虚拟实例,它的RAM是我桌面的5倍,处理器的能力是我桌面的5倍,我注意到它的运行速度完全一样。服务器运行进程,但有CPU周期和RAM可用。也许限制因素是磁盘速度。但是我有很多羊。我是否应该尝试以某种方式将文件加载到内存中?欢迎对处理大型文件的php命令行脚本的进一步优化提出任何建议!

    5 回复  |  直到 10 年前
        1
  •  3
  •   Pete Duncanson    16 年前

    你不会喜欢的,但是……听起来你在手头的任务中使用了错误的语言。如果你想在速度上有一些巨大的飞跃,那么下一步就是向编译语言提供一个端口。编译语言的运行速度比脚本语言快得多,所以您将看到处理时间的减少。

    此外,您还可以使用内置命令将数据转储到数据库中。Postgres有一个(Dump?Load?类似的东西)可以读取一个以制表符分隔的文本文件,其中的列与表中的列匹配。这将允许您只关注以正确的格式获取文本文件,然后用一个命令将其放入数据库,并让它处理优化,而不是自己。

    我们在一个.net应用程序中做了类似的事情,它每天早上在每一行上执行RegExp,通过咀嚼20Gb的文件,在内存中为唯一记录保留哈希,然后将新记录插入数据库。然后,我们使用Ruby脚本轻松地写出9000多个JS文件(这是最慢的部分)。我们以前也用Ruby编写导入程序,整个过程花了3个多小时,用.net重新编写整个过程大约需要30-40分钟,其中20分钟是缓慢的Ruby脚本(尽管它做得足够好,但不值得再优化)。

        2
  •  3
  •   troelskn    16 年前

    这类任务的两个重要设计建议:

    如果您的mysql存储类型支持事务(表必须是InnoDB),则可以使用它们进行优化。启动事务并处理f.ex。100k行,然后通过提交事务并打开一个新事务来刷新。这是因为MySql只更新索引一次,而不是每行更新一次。

    最后,如果其他方法都不起作用,您可以从等式中删除php并使用 LOAD DATA INFILE . 您可能需要首先使用php或其他文本处理语言(awk或sed具有非常好的性能配置文件)预处理文件

        3
  •  2
  •   Pascal MARTIN    16 年前

    您所花费的时间在不同的机器之间是相似的,可能是因为PHP脚本和MySQL服务器之间的通信:对于每个MySQL请求:

    • 您必须将该请求发送到MySQL服务器(通过网络或本地套接字; 需要时间 )
    • MySQL服务器必须处理数据(存储数据、创建索引、使用锁以确保安全性等等)
    • 每次都是这样。

    需要时间的可能并不真正在PHP方面;最有可能的是,它位于PHP和MySQL之间——对此您可能无能为力。

    如果你有一台相当强大的机器,我建议你:

    • 将数据拆分为X(不太复杂;例如X=6)部分
    • 启动脚本6次。

    脚本的第一次并行执行将处理的数据减少6倍;其他人也一样。。。它们将并行工作。。。因此,最终,整个过程所需的时间可能会减少4倍:-)

    这可能不会减少6倍的时间:使用并行化意味着在机器上增加一些负载,MySQL将有一些并发请求——但只要有几个并行进程,就可以了。

    附带说明:从PHP执行此操作可能不是最好的事情。以下是我可以思考的另一种方式:

      • 读取输入文件
      • 生成插入请求(但不将请求发送到MySQL服务器)
      • 将这些请求写入文件
    • 当文件中包含数百万行的所有请求时:
      • 一次性将该文件发送到MySQL。
      • mysql --host=HOST --user=USER --password=PASSWORD DATABASE_NAME < inserts-commands.sql "

    这样,只需确保文件中的SQL请求是正确的,然后MySQL一次导入所有内容:您不必为每个请求从PHP到MySQL,它应该运行得更快。

    希望这有帮助,玩得开心!

        4
  •  1
  •   TheHippo    16 年前

    除了脚本的优化之外,您建议尝试任何PHP加速器(例如: eaccelerator.net )。如果这没有帮助,我建议使用专门为此类任务设计的语言/平台。

        5
  •  0
  •   ftrotter mario    10 年前

    几乎所有其他答案都指出了这一点。PHP不太适合这种处理。

    尤其是现在HADOOP等人已经基本上使这种特定类型的任务在云中完全并行化。

    但是,某些地方的人可能需要像我一样使用PHP来处理大型文件。

    有鉴于此,我应该指出,新的Facebook工具 xhprof

    如果向其发送以下命令以启动:

    xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY );
    

    您可以很容易地看到您自己的代码的特定部分花费了这么多时间。

    -英尺

    推荐文章