代码之家  ›  专栏  ›  技术社区  ›  Hailwood

这段代码需要循环350万行,我怎样才能使它更有效率?

  •  6
  • Hailwood  · 技术社区  · 14 年前

    我有一个csv文件,里面有350万个代码。
    我要指出的是,这只会是这一次。

    age9tlg,  
    rigfh34,  
    ...
    

    这是我的密码:

    ini_set('max_execution_time', 600);
    ini_set("memory_limit", "512M");
    $file_handle = fopen("Weekly.csv", "r");
    while (!feof($file_handle)) {
        $line_of_text = fgetcsv($file_handle);
    
        if (is_array($line_of_text))
            foreach ($line_of_text as $col) {
                if (!empty($col)) {
                    mysql_query("insert into `action_6_weekly` Values('$col', '')") or die(mysql_error());
                }
        } else {
            if (!empty($line_of_text)) {
                mysql_query("insert into `action_6_weekly` Values('$line_of_text', '')") or die(mysql_error());
            }
        }
    }
    fclose($file_handle);
    

    这个密码会在我身上半途而废吗? 我的内存和最大执行时间是否足够高?

    注意: 此代码将在本地主机上运行,并且数据库位于同一台PC上,因此延迟不是问题。



    下面是另一个可能的实现。
    $file_handle = fopen("Weekly.csv", "r");
    $i = 0;
    $vals = array();
    while (!feof($file_handle)) {
        $line_of_text = fgetcsv($file_handle);
    
        if (is_array($line_of_text))
            foreach ($line_of_text as $col) {
                if (!empty($col)) {
                    if ($i < 2000) {
                        $vals[] = "('$col', '')";
                        $i++;
                    } else {
                        $vals = implode(', ', $vals);
                        mysql_query("insert into `action_6_weekly` Values $vals") or die(mysql_error());
                        $vals = array();
                        $i = 0;
                    }
                }
            } else {
            if (!empty($line_of_text)) {
                if ($i < 2000) {
                    $vals[] = "('$line_of_text', '')";
                    $i++;
                } else {
                    $vals = implode(', ', $vals);
                    mysql_query("insert into `action_6_weekly` Values $vals") or die(mysql_error());
                    $vals = array();
                    $i = 0;
                }
            }
        }
    }
    fclose($file_handle);
    

    如果我要使用这个方法,我可以设置的最大值是什么?



    所以,我发现我可以用
    LOAD DATA LOCAL INFILE  'C:\\xampp\\htdocs\\weekly.csv' INTO TABLE  `action_6_weekly` FIELDS TERMINATED BY  ';' ENCLOSED BY  '"' ESCAPED BY  '\\' LINES TERMINATED BY  ','(`code`)
    

    但现在的问题是,我对csv格式的看法是错误的, 实际上是4个代码然后换行, 所以 fhroflg、qporlfg、vcalpfx、rplfigc、,

    ...

    所以我需要能够指定以
    Here .



    将其设置为执行20k行的批量插入,使用
    while (!feof($file_handle)) {
       $val[] = fgetcsv($file_handle);
       $i++;
       if($i == 20000) {
          //do insert
          //set $i = 0;
          //$val = array();
       }
    }
    
    //do insert(for last few rows that dont reach 20k
    

    但它在这一点上就死了,因为出于某种原因,$val包含75k行,你知道为什么吗?
    注:上述代码已简化。

    6 回复  |  直到 7 年前
        1
  •  21
  •   user410344 user410344    14 年前

    我怀疑这将是流行的答案,但我会让你的php应用程序运行 mysqlimport 在csv文件上。当然,它的优化远远超出了您在php中所要做的。

        2
  •  3
  •   NullUserException Mark Roddy    14 年前

    通过我?我的记忆和马克斯 执行时间够长吗?

    你为什么不试试看呢?

    你可以调整两个内存( memory_limit max_execution_time )限制,所以如果你真的要用它,那应该不是问题。

    请注意,MySQL支持延迟和多行插入:

    INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);
    

    http://dev.mysql.com/doc/refman/5.1/en/insert.html

        3
  •  1
  •   Matthew Lock fge    14 年前
    1. 一定要有 在表上,因为索引会减慢插入速度(在完成所有插入之后添加索引)
    2. 而不是在循环的每个调用中创建新的SQL语句 Prepare the SQL 语句,并使用循环内的参数执行准备好的语句。根据数据库的不同,这可以加快堆的速度。

    在使用perl将大型Access数据库导入Postgres时,我已经完成了上述操作,并将插入时间缩短到30秒。我本应该使用导入工具,但我希望perl在插入时强制执行一些规则。

        4
  •  0
  •   deceze    14 年前

    另外,您应该在命令行上运行它,这样就不需要担心执行时间限制。

        5
  •  0
  •   user400389 user400389    14 年前

    我希望没有一个web客户端正在等待对此的响应。除了调用已经引用的import实用程序之外,我会将此作为一个作业启动,并几乎立即将反馈返回给客户机。让insert循环在某个地方更新完成的百分比,以便最终用户可以检查状态,如果您必须这样做的话。

        6
  •  0
  •   iWantSimpleLife    14 年前

    两种可能的方法。

    2) 让页面处理1000行(或任意N行。。。然后将一个java脚本发送到浏览器,用一个新参数刷新它自己,以告诉脚本处理接下来的1000行。您还可以在发生这种情况时向用户显示状态。唯一的问题是,如果页面不知何故没有刷新,那么导入就会停止。