【问题标题】:PHP script with MySQL query timing out带有 MySQL 查询超时的 PHP 脚本
【发布时间】:2017-05-03 14:49:03
【问题描述】:

我在运行将数据插入 MySQL 的 PHP 脚本时遇到问题。我得到的错误是“504 Gateway Time-out nginx” 当 PHP 页面被这个超时卡住时,已经向数据库输入了 10,102 行数据。我计划在一次加载的脚本中插入 160,000 行。

我通过为 SQL 使用准备好的语句使我的代码更高效。 SQL也是这样设置的:

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

我已阅读 SO PHP script times outHow to keep a php script from timing out because of a long mysql query

我尝试在代码的开头添加,但似乎没有什么不同:

set_time_limit(0);
ignore_user_abort(1);

谁能告诉我数据以将数据集拆分为块并为每个块插入数据?

我将在下面显示插入 MySQL 的代码部分

 // prepare and bind
$stmt = $link->prepare("INSERT INTO MyGuests (`eventID`,`location`,`date`,`barcode`,`runner`,`time`,`Run Points`,`Volunteer Points`,`Gender`, `Gender pos`) VALUES (?,?,?,?,?,?,?,?,?,?)");
$stmt->bind_param("isssssiisi", $eventID,$location,$date,$barcode,$runner,$time,$runpoints,$volpoints,$gender,$genderpos);

// set parameters and execute
for( $x=0; $x < count($array_runner); $x++ ){
    $eventID=null;
    $barcode=$array_barcode[$x];
    $runner=$array_runner[$x];
    $time=$array_time[$x];
    $runpoints=$array_score[$x];
    $volpoints=' ';
    $gender=$array_gender[$x];
    $genderpos=$array_gender_pos[$x];

    $stmt->execute();

}

$stmt->close();
$link->close();

我是使用 MySQL 的新手,正在寻找有关此问题的一些指导。

【问题讨论】:

  • 我认为你无权更改php时间限制,在这种情况下你没有任何机会通过这种方式解决这个问题。您可以将 SQL 查询拆分为单独的部分
  • 您能否将这个脚本作为 PHP CLI 运行,即从命令行运行!没有应用于 CLI 的 max_execution_time
  • 感谢您的评论彼得。啊“没有权利”很烦人,这个项目只托管在共享服务器上的 iPage 上,并且没有使用专用服务器/VPS 的计划。您能否提供任何将 SQL 拆分为单独部分的代码?

标签: php mysql nginx mysqli


【解决方案1】:

set_time_limit(0); 在执行时重置计数。它不会更改php.ini 中的max_execution_time,因此要使其具有任何有用的效果,您必须在循环中运行它。

 // prepare and bind
$stmt = $link->prepare("INSERT INTO MyGuests (`eventID`,`location`,`date`,`barcode`,`runner`,`time`,`Run Points`,`Volunteer Points`,`Gender`, `Gender pos`) VALUES (?,?,?,?,?,?,?,?,?,?)");
$stmt->bind_param("isssssiisi", $eventID,$location,$date,$barcode,$runner,$time,$runpoints,$volpoints,$gender,$genderpos);

// set parameters and execute
for( $x=0; $x < count($array_runner); $x++ ){
    $eventID=null;
    $barcode=$array_barcode[$x];
    $runner=$array_runner[$x];
    $time=$array_time[$x];
    $runpoints=$array_score[$x];
    $volpoints=' ';
    $gender=$array_gender[$x];
    $genderpos=$array_gender_pos[$x];

    $stmt->execute();

    // every 5000 times through the loop reset the timeout
    if ( $x % 5000 == 0 ) {
        set_time_limit(30);
    }
}

$stmt->close();
$link->close();

当然,您可以使用 5000 的值来减少重置的频率。

来自手册:

调用时,set_time_limit() 会从零重新启动超时计数器。换句话说,如果超时是默认的 30 秒,并且在脚本执行后 25 秒调用了 set_time_limit(20) 等调用,则脚本将在超时之前总共运行 45 秒。

【讨论】:

  • set_time_limit 与 504 网关超时无关 nginx
  • @YourCommonSense 好吧,据我所知,这可能是由超过 max_execution_time 引起的!虽然我承认还有很多其他原因
  • 感谢@RiggsFolly 提供此代码,我已尝试在循环中使用 set_time_limit() 但脚本仍停留在 10,102 行数据。
  • @Jeanclaude 倒霉,抱歉不是你的问题
  • @RiggsFolly 不用担心,我正在尝试相同的代码,但时间限制更长。所以我刚刚用 set_time_limit(360) 运行了代码,它在删除之前已经提取了 15,374 行数据。这是我插入数据库的最大数据量,只有一个运行过!另一方面,iPage 网络托管的人告诉我,我不能在共享托管服务器上使用 set_time_limit()。因此,也许我没有太多控制权,但脚本刚刚使用您提到的代码提取了这么多数据。再次感谢
【解决方案2】:

如果您在具有如此多行的循环中使用查询,它肯定会卡住。

我可以建议的最佳方法是简单地处理要插入到 PHP 字符串中的所有数据,然后触发单个查询来插入数据。

让我详细说明

$data_to_insert = '' // will contain all data to inserted
$count = 1;
$eventID = null; // if it is null for all rows

for( $x=0; $x < count($array_runner); $x++ )
{    
    if($count == 1)  // checking if it is the first value to be inserted
    {
        $data_to_insert = "(";
        $count = 2;
    }
    else // with second value onwards
    {
        $data_to_insert = ",(" ;
    }

    $data_to_insert = $data_to_insert .   $eventID . ",";
    $data_to_insert = $data_to_insert . "'".   $barcode . "'";
    $data_to_insert = $data_to_insert . "'".   $array_runner[$x] . "'";
    $data_to_insert = ")";
}
// so in the last $data_to_insert should look like this
// $data_to_insert =  (eventid1 , 'barcode1', 'runner1'), (eventid2 , 'barcode2', 'runner2') and so on...

然后触发查询

mysqli_query("INSERT INTO MyGuests (`eventID`,`barcode`,`runner`)  values" . $data_to_insert);
// which would look like
// INSERT INTO MyGuests (`eventID`,`barcode`,`runner`)  values (eventid1 , 'barcode1', 'runner1'), (eventid2 , 'barcode2', 'runner2')

注意: 我的代码中可能存在一些语法错误,但您可以从这里得到逻辑。

【讨论】:

    猜你喜欢
    • 2010-09-26
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2011-09-01
    • 2011-01-14
    相关资源
    最近更新 更多