在 PHP 中执行大型 SQL 查询字符串时出现“内存不足”错误
Posted
技术标签:
【中文标题】在 PHP 中执行大型 SQL 查询字符串时出现“内存不足”错误【英文标题】:"Out of memory" error when executing large SQL query string in PHP 【发布时间】:2013-11-07 10:06:55 【问题描述】:我想将我的 MS Access 数据导入 mysql 数据库。我正在使用xampp
。我编写了获取 Access 表并创建查询字符串的 php 代码。当我执行我的程序时,它给了我以下错误:
内存不足(需要 2465528 字节)
我的代码是:
<?php
$conn=odbc_connect('my','','');/* connected */
$sql="SELECT * FROM mytable";
$rs=odbc_exec($conn,$sql);
$sqlstr="";
$tablefields=array("Name","City","State");
$sqlstr="INSERT INTO `mytable`(";
$temp=0;
for($i=0;$i<count($tablefields)-1;$i++)
$sqlstr.="`".$tablefields[$i]."`";
if($temp==count($tablefields)-2)
else
$sqlstr.=",";
$temp++;
$sqlstr.=") VALUES";
//echo $sqlstr;
//return;
$sqlstr.="(";
while($row = odbc_fetch_array($rs))
$temp=0;
foreach ($row as $key => $value)
$sqlstr.="'".$value."'";
if($temp==count($row)-1)
$sqlstr.="),(";
else
$sqlstr.=",";
$temp++;
//echo $sqlstr;
$sqlstr.=")";
connection();
$res=mysql_query($sqlstr)or die (mysql_error());
function connection()
$host="localhost";
$user="root";
$pass="";
$database="mydatabase";
$cnx=mysql_connect($host, $user, $pass);
mysql_connect($host, $user, $pass);
echo (mysql_error($cnx));
mysql_select_db($database, $cnx);
echo (mysql_error($cnx));
return $cnx;
?>
我确实在php.ini
中更改了max_execution_time = 3600
和memory_limit = -1
在my.ini
key_buffer = 200M
sort_buffer_size = 200M
read_buffer = 200M
write_buffer = 200M
谁能告诉我问题出在哪里?
【问题讨论】:
更改后是否重启了xampp?mytable
的内容是什么?有没有 LOB?
是的,我重新启动了 xampp。mytable 包含 80 列和 100mb 大小。它包含近 2 lac 的记录。
您是否尝试过使用$sql="SELECT TOP 10 * FROM mytable";
来验证它是否确实适用于较小的批次?
@Gord Thompson 是的,它适用于小数据。
【参考方案1】:
对于处于类似情况的任何未来读者,更更好的方法是使用准备好的语句来执行 INSERT 操作。优点包括:
您不必猜测一批插入的“正确”尺寸应该是多少。 代码更易于维护和扩展。 如果文本字段包含单引号,它不会爆炸。 它不易受到 SQL 注入问题的影响。 能够正确处理 Null 值。<?php
$tablefields=array("Name","City","State");
$myDb = new PDO('mysql:host=localhost:3307;dbname=myDb', 'root', 'whatever');
$myDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$mySt = $myDb->prepare("TRUNCATE TABLE mytable");
$mySt->execute();
$params = array_fill(0, count($tablefields), '?');
$sqlstr = "INSERT INTO mytable (`" . implode("`,`", $tablefields) .
"`) VALUES (" . implode(",", $params) . ")";
// i.e., INSERT INTO mytable (`Name`,`City`,`State`) VALUES (?,?,?)
$mySt = $myDb->prepare($sqlstr);
$accDb = new PDO('odbc:' .
'Driver=Microsoft Access Driver (*.mdb, *.accdb);' .
'Dbq=C:\\Users\\Public\\Database1.accdb;');
$accDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sqlstr = "SELECT [" . implode("],[", $tablefields) . "] FROM myTable";
// i.e., SELECT [Name],[City],[State] FROM myTable
$accSt = $accDb->prepare($sqlstr);
$accSt->execute();
$rowCount = 0;
while ($row = $accSt->fetch())
for ($i = 0; $i < count($tablefields); $i++)
$params[$i] = $row[$tablefields[$i]];
$mySt->execute($params);
$rowCount++;
echo $rowCount . " row(s) copied.<br />";
【讨论】:
【参考方案2】:每隔几百条记录插入一次。像这样的东西:-
<?php
$conn=odbc_connect('my','','');/* connected */
$sql="SELECT * FROM mytable";
$rs=odbc_exec($conn,$sql);
$sqlstr="";
$tablefields=array("Name","City","State");
$sqlhead="INSERT INTO `mytable`(`".implode("`,`", $tablefields)."`) VALUES ";
connection();
$sqlitem = array();
while($row = odbc_fetch_array($rs))
$temp=0;
if (count($sqlitem) > 255)
$res=mysql_query($sqlhead.implode(',', $sqlitem))or die (mysql_error());
$sqlitem = array();
$sqlitem[] = "('".implode("','",$row)."')";
if (count($sqlitem) > 0)
$res=mysql_query($sqlhead."(".implode('),(', $sqlitem).")")or die (mysql_error());
function connection()
$host="localhost";
$user="root";
$pass="";
$database="mydatabase";
$cnx=mysql_connect($host, $user, $pass);
mysql_connect($host, $user, $pass);
echo (mysql_error($cnx));
mysql_select_db($database, $cnx);
echo (mysql_error($cnx));
return $cnx;
?>
您可以通过将插入转移到一个类中(而不仅仅是使用数组)来更简洁地做到这一点。传递每一行以插入类,如果当前总数大于 X 则执行插入,并且还从类中的析构函数执行插入。如果您需要进行更多插入,则不必在循环结束时做出决定。
注意,mysql_* 函数已被弃用,您可能应该改用 mysqli_* 函数。
【讨论】:
非常感谢 kickstart...感谢您的回复。它按我的意愿工作。以上是关于在 PHP 中执行大型 SQL 查询字符串时出现“内存不足”错误的主要内容,如果未能解决你的问题,请参考以下文章
使用 JDBC 驱动程序执行 Sql 查询时出现 NetworkOnMainThreadException
在apache spark上执行sql查询时出现arrayindexoutofbound异常
在 SQL Server 2008 中执行视图时出现“超时已过期”错误