我有一個大約 5mb(約 45,000 行)的 .csv 檔案。我需要做的是遍歷檔案的每一行并檢查每行中的 ID 是否已經在我的資料庫中的表中。如果是,我可以從檔案中洗掉該行。
我對最節省記憶體的方法進行了大量研究,因此我一直在使用一種方法,將不需要洗掉的行寫入臨時檔案,然后將該檔案重命名為原始檔案。下面的代碼:
$file= fopen($filename, 'r');
$temp = fopen($tempFilename, 'w');
while(($row = fgetcsv($file)) != FALSE){
// id is the 7th value in the row
$id = $row[6];
// check table to see if id exists
$sql = "SELECT id FROM table WHERE id = $id";
$result = mysqli_query($conn, $sql);
// if id is in the database, skip to next row
if(mysqli_num_rows($result) > 0){
continue;
}
// else write line to temp file
fputcsv($temp, $row);
}
fclose($file);
fclose($temp);
// overwrite original file
rename($tempFilename, $filename);
問題是,我在執行這段代碼時遇到了超時。我能做些什么來提高代碼效率?
uj5u.com熱心網友回復:
您每行觸發一個資料庫查詢,也就是 45.000 個查詢……這需要太多時間。
最好在回圈之前進行查詢并將現有 id 讀入查找陣列,然后僅在回圈中檢查此陣列。
偽代碼:
$st = query('SELECT id FROM table');
while ($row = $st->fetch()) {
$lookup[ $row['id'] ] = $row['id'];
}
// now read CSV
while($row = fgetcsv($h)) {
$id = $row[6];
if (isset($lookup[ $id ])) {
// exist...
continue;
}
// write the non-existing id to different file...
}
編輯:假設記憶體不足以容納資料庫中的 100 萬個整數。如何仍然有效地完成它?
將 CSV 中的 id 收集到一個陣列中。撰寫一個查詢以查找資料庫中的所有這些 id 并收集(它可以是最大的,就像在 CSV 中一樣多)。現在array_diff()檔案中的 id 和資料庫中的 id - 那些剩余的 id 存在于 CSV 但不存在于資料庫中。
偽代碼:
$ids_csv = [];
while($row = fgetcsv($h)) {
$id = row[6];
$ids_csv[] = intval($id);
}
$sql = sprintf('SELECT id FROM table WHERE id IN(%s)', implode(',', $ids_csv));
$ids_db = [];
$st = query($sql);
while ($row = $st->fetch()) {
$ids_db[] = $row['id'];
}
$missing_in_db = array_diff($ids_csv, $ids_db);
uj5u.com熱心網友回復:
- 我會使用
LOAD DATA INFILE:https
://dev.mysql.com/doc/refman/8.0/en/load-data.html 您的資料庫用戶需要擁有FILE資料庫權限才能使用。將 csv 檔案讀入單獨的表中。 - 然后你可以運行一個查詢來洗掉已經存在的 id (delete from join ...)
- 并匯出完好無損的行。
其他選項是使用回圈將 csv 檔案插入單獨的表中,然后繼續執行步驟 2。
更新:我使用LOAD DATA INFILE最多 200 萬行的 csv 檔案(目前)并使用大查詢進行一些批量資料操作,它非常快,我會推薦這條路線用于包含 > 100k 行的檔案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/520941.html
標籤:phpmysqlCSV
