【发布时间】:2014-05-30 15:03:10
【问题描述】:
我有一个包含 150,000 行的文本文件(本质上是一个没有扩展名的 csv)。我需要按键删除重复项,然后将它们插入数据库。我正在尝试 fgetcvs 逐行读取它,但我不想进行 150,000 次查询。所以这就是我到目前为止想出的:(请记住我正在使用 laravel)
$count = 0;
$insert = [];
if (($handle = fopen("myHUGEfile.txt", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$count++;
//See if this is the top row, which in this case are column headers
if ($count == 1) continue;
//Get the parts needed for the new part
$quantity = $data[0];
$part_number = $data[1];
$manufacturer = $data[2];
$new_part = [
'manufacturer' => $manufacturer,
'part_number' => $part_number,
'stock' => $quantity,
'price' => '[]',
'approved' => 0,
];
$insert[] = $new_part;
}
fclose($handle);
} else {
throw new Exception('Could not open file for reading.');
}
//Remove duplicates
$newRows = [];
$parsedCount = 0;
foreach ($insert as $row) {
$x = 0;
foreach ($newRows as $n) {
if (strtoupper($row['part_number']) === strtoupper($n['part_number'])) {
$x++;
}
}
if ($x == 0) {
$parsedCount++;
$newRows[] = $row;
}
}
$parsed_rows = array_chunk($newRows, 1000, true);
$x = 0;
foreach ($parsed_rows as $chunk) {
//Insert
if (count($chunk) > 0)
if (DB::table('search_parts')->insert($chunk))
$x++;
}
echo $x . " chunks inserted.<br/>" . $count . " parts started with<br/>" . $parsedCount . " rows after duplicates removed.";
但它非常笨拙,我只测试了超过 1000 行,它可以使用 localhost。但我担心如果我将它推向生产,它将无法处理所有 150,000 行。该文件大约 4mb。
有人可以告诉我一个更好更有效的方法吗?
【问题讨论】:
-
为什么不将文件放入临时数据库,然后在那里进行重复消除?一次性处理整个数据集比每行更容易处理“这已经存在了吗?”查询。
-
在 LOAD DATA INFILE 中酌情使用 REPLACE/IGNORE,就不会出现此类问题