IMDB datasets Import
Was man falsch und besser machen kann
IMDB bietet ihre Daten zur nicht kommerziellen Nutzung zu Verfügung.
Für die Nutzung der Daten plane ich den Import in eine MySQL Datenbank. Da ich auf die schnelle nichts einfaches und praktikables gefunden habe, schreibe ich den Import selbst.
Dabei bin ich über ein Szenario gestolpert an dem man zeigen kann so ist gut und so ist es besser.
Folgend ein Abschnitt meines ersten Entwurfs, aus der tsv Datei die Daten in eine Tabelle einzulesen: (Es ist nicht der komplette Code dargestellt, nur der wichtige Teil)
if (($handle = fopen($file, "r")) !== FALSE) {
// skip first line as it should be column names
fgetcsv($handle, 1000, "\t");
$linesInFile = $this->_linesInFile($file);
try {
$queryStmt = $this->_DB->prepare("INSERT IGNORE INTO `".$this->_db_table_name."`
VALUES(?,?,?,?,?,?,?,?)");
} catch (Exception $e) {
echo "Error while preparing sql statement.".$e->getMessage()."\n";
return false;
}
$i=0;
while (($data = fgetcsv($handle, 1000, "\t")) !== FALSE) {
try {
$queryStmt->bind_param('sisssssi',
$data[0],
$data[1],
$data[2],
$data[3],
$data[4],
$data[5],
$data[6],
$data[7]
);
$queryStmt->execute();
$i++;
echo "Inserting: $i/$linesInFile\r";
} catch (Exception $e) {
echo "Failed to execute the query: ".$e->getMessage()."\n";
return false;
}
}
$queryStmt->close();
fclose($handle);
echo "Import complete. Inserted $i rows\n";
}
Das Ergebnis dieser Art von Abarbeitung nach 10k Zeilen:
Inserting: 10210/20834144
real 0m31.936s
user 0m0.720s
sys 0m0.148s
Das dauert ja ewig. Denn in MB gemessen sind es nicht viele Daten. Aber bei ca. 20Mio. Einträge die dann in der Tabell vorhanden sind, merkt man dies schon.
Hier nur der Umbau an dem ich bemerkte das es schneller geht.
if (($handle = fopen($file, "r")) !== FALSE) {
// skip first line as it should be column names
fgetcsv($handle, 1000, "\t");
$linesInFile = $this->_linesInFile($file);
$queryStrStart = "INSERT IGNORE INTO `".$this->_db_table_name."` VALUES ";
$queryStr = '';
$total=0;
while (($data = fgetcsv($handle, 1000, "\t")) !== FALSE) {
$queryStr .= "(
'".$this->_DB->real_escape_string($data[0])."',
'".$this->_DB->real_escape_string($data[1])."',
'".$this->_DB->real_escape_string($data[2])."',
'".$this->_DB->real_escape_string($data[3])."',
'".$this->_DB->real_escape_string($data[4])."',
'".$this->_DB->real_escape_string($data[5])."',
'".$this->_DB->real_escape_string($data[6])."',
'".$this->_DB->real_escape_string($data[7])."'
),";
$total++;
if(isset($queryStr[1000000])) {
$this->_DB->query($queryStrStart.trim($queryStr,","));
$queryStr = '';
}
echo "Inserting: $total/$linesInFile\r";
}
fclose($handle);
echo "Import complete. Inserted $total rows\n";
Dabei wird die Möglichkeit verwendet das ein INSERT so aussehen kann INSERT ... VALUES (),(),()...
Also mehr Daten auf einmal. Damit der einzel Query nicht zu groß wird frage ich auf eine maximale Länge
von 1000000 Zeichen ab. Dies kann je nach System aber abweichen.
Hier das Ergebnis nach ca 600k Zeilen:
Inserting: 595246/20834144
real 0m6.952s
user 0m3.038s
sys 0m0.822s