【问题标题】:My PHP scripts give me 500 Internal Server Error when they're intense我的 PHP 脚本在紧张时给了我 500 内部服务器错误
【发布时间】:2011-08-23 20:48:40
【问题描述】:

长话短说,如果我将 PHP 脚本分解成小块,我最终可以运行所有代码。但是,我现在有一个脚本,它读取一个巨大的 CSV 文件并将每一行插入到 MySQL 数据库中。每次我想更新我的网站时,我都不必经历拆分文件的繁重过程,我只想让这个脚本按照我知道的方式工作。

我之前已经让它在不同的网络服务器上插入大约 10,000 行,但文件中至少有 7 倍,而且它在完成之前就崩溃了。

因此,故事是,在一台服务器上它在它应该停止之前停止,而在另一台服务器上它根本不运行......它只是在大约 30 秒后突然出现 500 错误。

当脚本终止时,Apache 错误日志给了我这些行:

[Tue Aug 23 13:09:04 2011] [warn] [client 71.168.85.72] mod_fcgid: read data timeout in 40 seconds
[Tue Aug 23 13:09:04 2011] [error] [client 71.168.85.72] Premature end of script headers: newcsvupdater.php

我在脚本的顶部有这两行:

set_time_limit(0);
ini_set('memory_limit','256M');

因为之前我遇到了致命的内存分配错误,因为显然将大文件拆分为数组会占用大量内存。

这是插入代码:

$file = "./bigdumbfile.csv";  // roughly 30mb

$handle = fopen($file, r);

$firstentry = 0;

while($csv = fgetcsv($handle))
{
    if($firstentry == 0)
    {
        $firstentry++;  // skips the top row of field names
    }
    else
    {         

      // unimportant conditional code omitted

        $checkforexisting = mysql_query("SELECT * FROM DB_TABLE WHERE ".
                "id_one = '".$csv[0]."' AND id_two = '".$csv[2]."'");

        $checknum = mysql_num_rows($checkforexisting);

        if($checknum == 0)
        {
            if(!mysql_query("INSERT INTO DB_TABLE ".
                       "(id_one, data_one, id_two, data_two, ".
                        /* so on for 22 total fields */") 
              VALUES ('".addslashes($csv[0])."', '".
                         addslashes($csv[1])."', '".
                         addslashes($csv[2])."', '".
                         addslashes($csv[3])."' "/* ditto, as above */))
            {                    
                exit("<br>" . mysql_error());
            }
            else
            {
                print_r($csv);
                echo " insert complete<br><br>";
            } 
        }            
    }
}        

echo "<br><b>DB_TABLE UPDATED"; 

我以前因此不得不拆分大型任务,我已经厌倦了。我敢肯定我做错了很多,因为我完全是自学成才的,而且通常写的东西相当于意大利面,所以不要退缩。

【问题讨论】:

  • 如果您已经超过了 40 秒的超时时间,那么您需要弄清楚为什么您的脚本如此缓慢并可能执行其他操作。我有一个导入大型 mysql 数据库的脚本。我用它在 3 小时内导入了一个 10GB 的数据库。

标签: php mysql apache


【解决方案1】:

要增加脚本的时间限制,您需要编辑站点的虚拟主机配置:

http://www.moe.co.uk/2009/08/17/php-running-under-mod_fcgid-read-data-timeout-in-40-seconds-on-plesk/

(mod_fcgid 的超时覆盖 PHP 的超时)

要使您的脚本更快(因此您可能不需要执行上述步骤,这在共享主机上可能无法实现),请尝试以下操作:

提前准备好所有要插入的信息以进行批量插入。查询应如下所示:

INSERT IGNORE INTO (id_one, data_one, id_two, data_two) VALUES
(1, 'apple', 3, 'banana'),
(4, 'pear', 5, 'orange)

IGNORE 部分应该具有提前检查记录是否已经存在的相同效果(如果存在,它就不会被插入,它将继续到下一个)。

【讨论】:

  • 删除检查重复条目的查询允许脚本快速且完美地运行。我想从现在开始我们要做的就是备份表,清空它,然后再把整个文件放好。在相关的说明中,我昨晚做了美味的意大利面酱......
【解决方案2】:

您可以使用 SQL 插入批量值,这应该会减少查询运行所需的时间(往返可能是您的瓶颈)。

INSERT INTO table (cola,colb...)
VALUES
  (vala,valb...),
  (valc,vald...)

大多数情况下,当您执行此类大型插入时,您希望异步执行,这意味着您将文件转储到某个地方,离线处理它,然后通知用户它已完成,而不是等待页面加载完成。

我还看到您在实际执行插入之前检查是否存在。您可能需要考虑选择“可能”匹配的行,然后在 PHP 端进行检查(使用哈希),而不是每次都运行该查询。

【讨论】:

  • 不仅如此,MySQL 还可以直接读取 CSV 文件。完全没有理由尝试用 PHP 编写它。
  • 除非您正在编写一个允许用户为要导入的 CSV 文件设置自己的标题名称的导入脚本。有人想要使用 PHP 来处理 CSV 而不是直接将其提供给数据库的原因有十几个。
【解决方案3】:

您似乎在 Apache 而不是 PHP 上超时。 set_time_limit 函数用于 php-script 和 apache 对此一无所知。

【讨论】:

    【解决方案4】:

    我的第一个直觉是在没有 PHP 的情况下使用 mysqlimport 或更好的 LOAD DATA INFILE 来完成所有这些工作。

    LOAD DATA INFILE ./bigdumbfile.csv INTO TABLE tbl_name;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-18
      • 2015-05-04
      • 1970-01-01
      • 1970-01-01
      • 2011-08-04
      • 2023-03-09
      相关资源
      最近更新 更多