我有一个运行mysql查询的php脚本,然后循环结果,并在该循环中还运行多个查询:
$sqlstr = "SELECT * FROM user_pred WHERE uprType != 2 AND uprTurn=$turn ORDER BY uprUserTeamIdFK";
$utmres = mysql_query($sqlstr) or trigger_error($termerror = __FILE__." - ".__LINE__.": ".mysql_error());
while($utmrow = mysql_fetch_array($utmres, MYSQL_ASSOC)) {
// some stuff happens here
// echo memory_get_usage() . " - 1241<br/>\n";
$sqlstr = "UPDATE user_roundscores SET ursUpdDate=NOW(),ursScore=$score WHERE ursUserTeamIdFK=$userteamid";
if(!mysql_query($sqlstr)) {
$err_crit++;
$cLog->WriteLogFile("Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid\n");
echo "Failed to UPDATE user_roundscores record for user $userid - teamuserid: $userteamid<br>\n";
break;
}
unset($sqlstr);
// echo memory_get_usage() . " - 1253<br/>\n";
// some stuff happens here too
}
更新查询永远不会失败。
出于某种原因,在memory_get_usage
的两次调用之间,添加了一些内存。因为大循环运行大约500.000次或更多次,最终它实际上增加了很多内存。这里有什么我想念的吗?
难道这可能是因为内存实际上并没有在两个调用之间添加,而是在脚本的另一个位置?
编辑:一些额外的信息: 循环之前它大约是5mb,循环之后大约440mb,每个更新查询增加大约250个字节。 (其余的内存将添加到循环中的其他位置)。 我没有发布更多“其他东西”的原因是因为它有大约300行代码。我发布了这个部分,因为它看起来是添加最多内存的地方。
答案 0 :(得分:4)
如果内存泄漏只是一个问题,如果它以“内存耗尽”错误查杀脚本。 PHP将很乐意自己垃圾收集任何异常的对象/变量,但收集器不会踢,直到它必须 - 垃圾收集可能是一个非常昂贵的操作。
即使您经常重复使用相同的对象/变量,看到内存使用量也会增加是正常的 - 直到内存使用率超过某个级别,收集器才会启动并清理房屋。
我怀疑如果您将用户ID分组并发布更少的更新,每次更改更多记录,您可以使运行速度更快。例如执行以下操作:
UPDATE user_roundscores SET ursUpdDate=NOW() WHERE ursUserTeamIdFK IN (id1, id2, id3, id4, id5, etc...)
而不是每个用户更新一次。通过数据库接口层的往返次数减少,服务器上的时间减少=运行速度更快。
同样,请考虑现在将其扩展到数百万用户的影响,正如您在评论中所说的那样。一百万次单独更新将花费非常少的时间来运行,因此NOW()
将不会是“常量”。如果完整运行需要5分钟,那么您将获得各种ursUpdDate
个时间戳。您可能需要考虑在服务器端变量中缓存单个NOW()
调用,并针对该变量发出更新:
SELECT @cachednow :p NOW();
UPDATE .... SET ursUpDate = @cachednow WHERE ....;
答案 1 :(得分:2)
最好的方法可能是获取所有userIds并将它们刷新到文件中。 然后运行一个新的脚本,用管道分叉x个工作无人机。然后给他们一个小的userIds列表,在他们完成每个列表时进行处理。使用多个cpus / cores / servers,您可以更快地完成任务。如果一个工人失败,只需启动一个新工人。 要将其他服务器用作工作者,可以使用curl / fopen / soap / etc从工作线程调用它们。
答案 2 :(得分:1)
我认为你应该在循环中的某个时刻尝试调用 - 来自评论:mysql_free_result()
。
值得注意的是mysql_query() 仅返回
SELECT
的资源,SHOW
,EXPLAIN
和DESCRIBE
次查询。
因此没有结果可以免费提供更新查询。
无论如何,你的方法不是最好的开始。改为尝试使用mysqli paramterized语句,或者(甚至更好)直接更新数据库中的行。看起来循环中的所有SQL都可以使用一个UPDATE语句来处理。
答案 3 :(得分:1)
您可能在每次迭代中看到额外的已用内存的部分原因是PHP尚未(还)垃圾收集不再引用的内容。
答案 4 :(得分:1)
来自php.net memory_get_usage manual:
参数
real_usage将此设置为TRUE以获取 从中分配的实际内存大小 系统。如果没有设置或FALSE只有 记录了emalloc()使用的内存。
将此参数设置为true,脚本显示内存没有增加,就像我预期的那样。
答案 5 :(得分:0)
unset
电话无意义/无关紧要。尝试使用mysql_free_result
- 它可能会产生一些影响。