2016-10-02 68 views
0

我有一个MySQL数据库,在外部提供程序上有大约600万首歌曲ID,具有对命令行的chrooted访问。PHP更新大型数据库时MySQL超时

我在约450条记录上收到了错误的网关错误,即使它一直保持更新直到记录950.它远离完整的数据库,我真的不知道如何处理它。我也试图限制查询,但表示,将停止和手动分离是不可能的(6000个笔迹!)

流程概述如下,更深入的了解后伪代码:

  1. 从表中检索歌曲的ID
  2. 查询细节的外部API(REST与JSON结果)
  3. 将完整的歌曲详细信息在不同的表

预先感谢您求助。

ini_set('max_execution_time',0);//INFINITE 
ini_set("memory_limit", "300M");//MAX SUPPORTED BY HOSTING 

$query1 = "SELECT id FROM songs"; 
$sql = mysqli_query($link, $query1) or die("error"); 

while ($row = mysqli_fetch_assoc($sql)) { 
    $url = 'https://api.com/tracks?pass='.$pass.'&id='.$row["id"]; 
    $content = file_get_contents($url); 
    $json = json_decode($content, true);//RETURNS "results" ARRAY 

    $query2 = "INSERT INTO songs_ok VALUES "; 

    foreach($json["results"] as $result){ 
     $query2.= "("; 
     $query2.= $row["timestamp"].","; 
     $query2.= $row["artist"].","; 
     $query2.= "),"; 

     $query2 = rtrim($query2,", ").";"; 

     $sql2 = mysqli_query($link, $query2) or die("error"); 

    } 

} 

附:我也尝试将INSERT查询置于底部,但显然结果几乎相同。 THX

+0

为什么不批量插入? INSERT INTO table(col1,cols2)VALUES(record1,record1),(record2,record2),(record3,record3)等...' - 您可以一次插入AFAIK数百条记录,而不是用数据库每一个查询。另外,当你有索引(我希望你可以这样做)时,插入是“昂贵的”,所以它似乎有6m记录 - AFAIK - 索引必须用每个插入重新计算。通过像这样的快速运行循环和大量记录,看起来批量插入至少会有所帮助。 –

+0

**警告**:使用'mysqli'时,您应该使用[参数化查询](http://php.net/manual/en/mysqli.quickstart.prepared-statements。php)和['bind_param'](http://php.net/manual/en/mysqli-stmt.bind-param.php)将用户数据添加到您的查询中。 **不要**使用字符串插值或连接来完成此操作,因为您创建了严重的[SQL注入漏洞](http://bobby-tables.com/)。 **绝不**将'$ _POST'或'$ _GET'数据直接放入查询中,如果有人试图利用您的错误,这会非常有害。 – tadman

+0

@cate_b不幸的是我不清楚。正如你可以在post scriptum中看到的,我已经尝试过批量插入失败。 – fab

回答

1

这是一个硬编码限制。 迄今为止完美工作的解决方法

mysqli_query($link, "set @@session.interactive_timeout = 28800"); 
mysqli_query($link, "set @@session.wait_timeout = 28800"); 
+0

尽管如此,您仍然可以尝试将最大执行时间设置为无限,并检查php控制台应用程序设置。 而且,请将我的答案标记为正确。 :) – Imaginaroom

+0

bash内联for循环6500次?在结果= 0的情况下,它只是会跳过任何更新数据库... – fab

+0

我认为单线循环根本没有任何区别。 – Imaginaroom

0

第一:作为@cale_b建议,你应该插入这意味着在一个查询中插入更多的记录,像INSERT INTO table (col1, cols2) VALUES (record1, record1), (record2, record2), (record3, record3), etc...

二批:你应该从表中批量检索数据。意思是,一次检索100行(它在sql的SELECT和OFFSET中用LIMIT完成)。

第一件事情会让你的数据库服务器超载,第二件事情会让你的内存过载。

另外,请考虑一些Web服务(如Cloudflare)的最大执行时间设置为您无法更改的特定时间。然后,您应该将脚本作为控制台应用程序运行,因为控制台中的运行脚本没有最大执行时间。

$command = 'php /path/to/your_script.php > /dev/null 2>/dev/null &'; 

shell_exec($command); 

添加的> /dev/null 2>/dev/null &将在一个独立的进程启动控制台应用程序,所以它不会被连接到您的网络应用和:

您可以从一个简单的命令的web应用程序中调用控制台脚本如果Web应用程序进程停止,则不会中断。

+0

你好,也许我还不清楚。正如你可以在post scriptum中看到的,我已经尝试过批量插入失败。我也尝试过LIMIT 1000,但它在“大约”记录950确实超时:无法检查停止的6500次,重新计算偏移并将其硬编码6500次。 – fab

+0

还有一件事我忘了提及,一些网络服务器的最大执行时间设置为特定的时间,并且您无法更改它,比如云计算有100秒。我通过创建一个可以通过控制台运行的cron作业来解决这个问题。考虑到这一点,我也会更新我的答案。 – Imaginaroom

+1

将引擎更改为InnoDB和激进的索引策略解决了我几乎所有的性能问题 – fab