Mass Importing into SQL Database from .csv File

If you have to import let’s say for example Country Name and County Code into a database from a CSV file like this: (source)

Code,English Name,French Name
AD,Andorra,Andorre
AE,United Arab Emirates,Émirats arabes unis
AF,Afghanistan,Afghanistan
AG,Antigua and Barbuda,Antigua-et-Barbuda

The database schema is as follows:

country_code {country_code,country_name}

In PHP, you could have done:

(Method 1)

$file_handle = fopen(dirname(__FILE__) .
               "/countries.csv", "r");
while (!feof($file_handle) ) {
	$line = fgetcsv($file_handle, 1024);
	$line[1] = mysql_real_escape_string($line[1]); 
	$sql = "INSERT INTO country_code 
	(country_code,country_name) 
	VALUES ('{$line[0]}','{$line[1]}');";
	$db->query($sql);
}
fclose($file_handle);


But it takes about 3 seconds to import the CSV attached. If you have a file with lets say with 50,000 records, it might take hours to run. It is really annoying to have Core i7 computers with lots of RAM and yet you run a process which takes hours to run using only 0 – 1% CPU.

I/O from the Hard Drive is limiting the speed tremendously as each time a record is being read, the HDD is accessed, MySQL then accesses the HDD to save and so on. Even a Solid State Drive (SSD) doesn’t solve the problem (I tried. Still takes hours).

I had to find a way to load a somewhat big chunk of the file into memory then execute the insert query for every 1000 records. I came up with the following code:

(Method 2)

$file_handle = fopen(dirname(__FILE__) 
	. "/countries.csv", "r");
$init_sql = "INSERT INTO country_code 
	(country_code,country_name) VALUES ";
$sql = $init_sql;
$count = 1;
$i = 0;
while (!feof($file_handle) ) {
	$line = fgetcsv($file_handle, 1024);
	$line[1] = mysql_real_escape_string($line[1]);
	$sql .= "('{$line[0]}','{$line[1]}'),";
	if($count++ >= 1000){
		$i++;
		$count = 0;
		$sql = rtrim($sql , ',');
		$sql .= ";";
		$db->query($sql);
		$sql = $init_sql;
	}
}
$sql = rtrim($sql , ",");
$sql .= ";";
$db->query($sql);
fclose($file_handle);

Method 1 exec time: 3.0624158382416 s
Method 2 exec time: 0.010763883590698 s

Method 2 is 284 x faster

The import time is considerably improved. According to my benchmarks, it is 270-285x faster.

I was once importing US ZIP codes in a database. It contained between 43k records. The second method allows importing it in less than 5 seconds 😉

Leave a Reply

Your email address will not be published. Required fields are marked *