我需要运行一个每日cron作业,迭代6 MB的CSV文件,将〜10,000个条目中的每一个插入到MySQL表中。我写的代码会挂起并在一段时间后产生超时。
if (($handle = fopen($localCSV, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$dbdata = array(
'SiteID' => $siteID,
'TimeStamp' => $data[0],
'ProductID' => $data[1],
'CoordX' => $data[2],
'CoordY' => $data[3]
);
$row++;
$STH = $DBH->prepare("INSERT INTO temp_csv (SiteID,TimeStamp,ProductID,CoordX,CoordY) VALUES (:SiteID,:TimeStamp,:ProductID,:CoordX,:CoordY)");
$STH->execute($dbdata);
}
fclose($handle);
echo $row." rows inserted.";
}
使用mysql_*
函数而不是PDO是理想的,因此我可以将值内容整合到一个查询中(尽管很大)但不幸的是我需要遵守一些指导原则(严格使用PDO)
我搜索了SO并且有非常相似的问题,但没有一个可以解决我的问题。我尝试的是以下内容:
1- Ran LOAD DATA INFILE
和LOAD DATA LOCAL INFILE
查询但仍然收到“找不到文件”错误,尽管该文件肯定存在777权限。数据库服务器和共享主机帐户位于不同的环境中。我尝试了相对和url路径到csv文件,但没有运气(在两种情况下都找不到文件)。
2-我将csv文件拆分为2个文件并在每个文件上运行脚本,以查看脚本挂起的阈值,但是在每个文件的情况下,它在表中插入了两次条目。
我无法访问php.ini
,因为它是共享主机帐户(Cloudsites),只能通过phpMyAdmin访问MySQL
。
我还能尽可能有效地尝试实现这一目标吗?
感谢任何帮助。
答案 0 :(得分:0)
代码对我来说没有错。它挂起,因为它只需要一段时间才能执行。您应该使用phps set_time_limit来防止超时。
if (($handle = fopen($localCSV, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
set_time_limit(30) // choose a value that works for you
// ... the rest of your script
更好的是,无论是开始处理csv的后台进程,它都需要某种锁定,因此它不会并行运行在多个实例中。如果您将状态写入磁盘上的文件,则可以轻松地将其呈现给用户。 这同样适用于cron脚本(如果您可以使用托管解决方案执行此操作)
使用PDO对我来说没问题。我不会想到一次插入csv的所有行,但是你也可以用PDO一次插入多行。为多行创建语句和数据数组。它可能看起来像这个草图(我没有执行它所以可能会有一些错误):
function insert_data($DBH, array $dbdata, array $values) {
$sql = "INSERT INTO temp_csv (SiteID,TimeStamp,ProductID,CoordX,CoordY) VALUES %1$s;";
$STH = $DBH->prepare(sprintf($sql, join(', ', $values)));
$STH->execute($dbdata);
}
if (($handle = fopen($localCSV, "r")) !== FALSE) {
$dbdata = array();
$values = array();
$row = 0;
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
if(!count($dbdata))
$dbdata['SiteID'] = $siteID;
$dbdata['TimeStamp_'.$row] = $data[0];
$dbdata['ProductID_'.$row] = $data[1];
$dbdata['CoordX_'.$row] = $data[2];
$dbdata['CoordY_'.$row] = $data[3];
$values[] = sprintf('(:SiteID_%1$s,:TimeStamp_%1$s,:ProductID_%1$s,:CoordX_%1$s,:CoordY_%1$s)', $row);
$row++;
if($row % 10 === 0) {
set_time_limit(30);
insert_data($DBH, $dbdata, $values);
$values = array();
$dbdata = array();
}
}
// insert the rest
if(count($values))
insert_data($DBH, $dbdata, $values);
fclose($handle);
echo $row." rows inserted.";
}
至少阅读php.ini配置的快捷方式是phpinfo。查看PHP手册,可以在运行时从代码中设置许多配置值。