我没想到这个剧本(扔掉)会泄漏,我还没弄清楚罪魁祸首是什么。你能发现什么吗?虽然这是丢失的代码,但我担心将来会重复这个。我从来没有在PHP中管理内存,但是由于数据库中的行数,它正在炸毁我的php实例(已经将内存增加到1Gb)。
加利福尼亚表特别大于其他表(目前2.2米行,因为我删除了重复的行)。我在第31行遇到了内存错误($ row = mysql_fetch_assoc($ res))
致命错误:允许的内存大小为1073741824字节(已尝试 在C:\ Documents and Settings \ R \ My Documents \ My中分配e 24字节) 第31行的网页\ cdiac \ cdiac_ dup.php
PHP 5.3.0,mysql 5.1.36。 wamp安装的一部分。
这是整个代码。这个脚本的目的是删除重复的条目(数据被获取到分段表中,当时速度要快得多,但现在我必须合并这些表。)
是什么原因造成的?我忽视的东西?或者我只是需要观察内存大小并在它变大时手动调用垃圾收集?<?php
define('DBSERVER', 'localhost');
define('DBNAME', '---');
define('DBUSERNAME', '---');
define('DBPASSWORD', '---');
$dblink = mysql_connect(DBSERVER, DBUSERNAME, DBPASSWORD);
mysql_select_db(DBNAME, $dblink);
$state = "AL";
//if (isset($_GET['state'])) $state=mysql_real_escape_string($_GET['state']);
if (isset($argv[1]) ) $state = $argv[1];
echo "Scanning $state\n\n";
// interate through listing of a state to check for duplicate entries (same station_id, year, month, day)
$DBTABLE = "cdiac_data_". $state;
$query = "select * from $DBTABLE ";
$query .= " order by station_id, year, month, day ";
$res = mysql_query($query) or die ("could not run query '$query': " . mysql_errno() . " " . mysql_error());
$last = "";
$prev_row;
$i = 1;
$counter = 0;
echo ".\n";
while ($row = mysql_fetch_assoc($res)) {
$current = $row["station_id"] . "_" . $row["year"] . "_" . sprintf("%02d",$row["month"]) . "_" . sprintf("%02d",$row["day"]);
echo str_repeat(chr(8), 80) . "$i $current ";
if ($last == $current) {
//echo implode(', ', $row) . "\n";
// merge $row and $prev_row
// data_id station_id, state_abbrev, year, month, day, TMIN, TMIN_flags, TMAX, TMAX_flags, PRCP, PRCP_flags, SNOW, SNOW_flags, SNWD, SNWD_flags
printf("%-13s %8s %8s\n", "data_id:", $prev_row["data_id"], $row["data_id"]);
if ($prev_row["data_id"] == $row["data_id"]) echo " + ";
$set = "";
if (!$prev_row["TMIN"] && $row["TMIN"]) $set .= "TMIN = " . $row["TMIN"] . ", ";
if (!$prev_row["TMIN_flags"] && $row["TMIN_flags"]) $set .= "TMIN_flags = '" . $row["TMIN_flags"] . "', ";
if (!$prev_row["TMAX"] && $row["TMAX"]) $set .= "TMAX = " . $row["TMAX"] . ", ";
if (!$prev_row["TMAX_flags"] && $row["TMAX_flags"]) $set .= "TMAX_flags = '" . $row["TMAX_flags"] . "', ";
if (!$prev_row["PRCP"] && $row["PRCP"]) $set .= "PRCP = " . $row["PRCP"] . ", ";
if (!$prev_row["PRCP_flags"] && $row["PRCP_flags"]) $set .= "PRCP_flags = '" . $row["PRCP_flags"] . "', ";
if (!$prev_row["SNOW"] && $row["SNOW"]) $set .= "SNOW = " . $row["SNOW"] . ", ";
if (!$prev_row["SNOW_flags"] && $row["SNOW_flags"]) $set .= "SNOW_flags = '" . $row["SNOW_flags"] . "', ";
if (!$prev_row["SNWD"] && $row["SNWD"]) $set .= "SNWD = " . $row["SNWD"] . ", ";
if (!$prev_row["SNWD_flags"] && $row["SNWD_flags"]) $set .= "SNWD_flags = '" . $row["SNWD_flags"] . "', ";
$delete = "";
$update = "";
if ($set = substr_replace( $set, "", -2 )) $update = "UPDATE $DBTABLE SET $set WHERE data_id=".$prev_row["data_id"]." and year=".$row["year"]." and month=".$row["month"]." and day=".$row["day"].";\n";
if ($row["data_id"] != $prev_row["data_id"]) $delete = "delete from $DBTABLE where data_id=".$row["data_id"]." and year=".$row["year"]." and month=".$row["month"]." and day=".$row["day"].";\n\n";
if ($update) {
$r = mysql_query($update) or die ("could not run query '$update' \n".mysql_error());
}
if ($delete) {
$r = mysql_query($delete) or die ("could not run query '$delete' \n".mysql_error());
}
//if ($counter++ > 5) exit(0);
}
else {
$last = $current;
unset($prev_row);
//copy $row to $prev_row
foreach ($row as $key => $val) $prev_row[$key] = $val;
}
$i++;
}
echo "\n\nDONE\n";
?>
答案 0 :(得分:2)
我会尝试两件事:
1)不是使用mysql_query
在循环内运行UPDATE和DELETE查询,而是将它们保存在文本文件中,以便稍后执行。例如:file_put_contents('queries.sql', $update, FILE_APPEND );
2)而不是在while ($row = mysql_fetch_assoc($res))
循环中执行所有操作,首先获取所有SELECT查询结果,然后关闭数据库连接以释放所有数据库资源,包括查询结果。只有在此之后,才执行循环过程。
如果在将数据库结果存储在一个数组中时内存不足,则可以尝试将结果保存在临时文件中(每行一个记录/ FILE_APPEND),然后在循环中使用此文件(读取一行)每条记录,使用fgets
函数。)
答案 1 :(得分:2)
更聪明地工作,而不是更难:
SELECT station_id, year, month FROM table
GROUP BY station_id, year, month
HAVING COUNT(*) > 1
这将为您提供不止一次出现在表格中的所有station_id /年/月元组。假设您的大多数数据都不是重复数据,这将为您节省大量内存,因为现在您只需要通过这些元组并修复与它们匹配的行。
答案 2 :(得分:0)
我在尝试追踪我的脚本上的内存使用问题时发现了这一点。解决了我的问题后,我觉得值得为下一个同样问题的人添加回复。
我使用的是mysqli,但同样适用于mysql。
我发现的问题是查询没有释放他们的结果。解决方案是在执行更新和删除查询后使用mysqli_free_result()。但更重要的是在循环的mysqli_query上我使用了* MYSQLI_USE_RESULT *的额外参数。这有副作用,因此请使用单独的连接进行更新和删除查询。