如何优化这个sql插入php代码?

时间:2016-05-18 16:10:32

标签: php mysql rdbms

我有mysql数据库,我想从PHP代码中插入大约40'000行,但是我的代码需要超过15分钟来插入行,有没有机会优化它?我的问题在哪里(PHP代码/数据库设计)?

以下是详细信息:

- 行数据存储在utf-8 txt文件中,值由“\ t”制表符分隔,每行设置在文件的一行中,如下所示

字符串视图:

"value1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\n"

文本阅读器视图:

value1     value2     value3     value4     value5
value1     value2     value3     value4     value5
value1     value2     value3     value4     value5
value1     value2     value3     value4     value5

- 数据库有3个表:

table1 countries fields(1) (NAME varchar -primarykey-)
table2 products fields(2) (HS varchar - primarykey-, NAME varchar) 
table3 imports fields (6) (product_hs varchar -foreignkey->products(HS),
counteryname varchar - foreignkey->countries (NAME),
year year,
units int,
weight int,
value int)        

- php code 就像这样

$conn = new mysqli($hn,$un,$pw,$db);
if($conn->connect_error) {die($conn->connect_error);}

$x = 0; // row counter
ini_set('max_execution_time', 3000);

while(!feof($filehandle)){
$x++;
echo $x . ":  ";
$fileline = fgets($filehandle);
$fields = explode("\t", $fileline);
$query = "INSERT INTO imports(product_hs,counteryname,year,units,weight,value) VALUES(" . "'" . $fields[0] ."','". $fields[1] . "','2014','". $fields[2] . "','" . $fields[3] . "','" . $fields[4] .  "');";
$result = $conn->query($query);
if(!$result) {
    echo $conn->error . "</br>";
}else{
    echo $result . "</br>";
}
};

首先我认为这是一个索引问题会降低插入速度,所以我从“进口”表中删除了所有索引,但它没有更快! 是数据库设计或我的PHP代码的问题?

还注意到浏览器在前5分钟通知“等待来自服务器的响应”,然后大部分剩余时间通知“从服务器传输数据”,这是因为响应html超过了行计数器1:1 </br> 2:1 </br> .....的40'000行(在php代码中声明)?

请考虑我是新手,谢谢。

1 个答案:

答案 0 :(得分:2)

非常感谢mr.tadmanmr.Hanlet Escaño以及mr.Uueerdomr.Julie Pelletier以及mr.Solarflare 在评论中帮助我。

我使用您在评论中建议的方法对我的PHP代码进行了3次不同的更改,然后我测试了结果,这里是测试结果。

3次测试的结论:正如mr.tadman建议的那样,关键在于LOAD DATA INFILE。它将执行时间大大缩短到不到7秒,这是3次测试。

原始代码: ~26分钟

enter image description here

测试1: ~34分钟

enter image description here

(正如先生Uueerdo建议我从循环中移除echo语句和行计数器)

while(!feof($filehandle)){
// $x++; // commented out
//echo $x . ":  "; // commented out
$fileline = fgets($filehandle);
$fields = explode("\t", $fileline);
$query = "INSERT INTO products(hs,arabicname,englishname) VALUES(" . "'" . str_replace("'", ".", $fields[0]) ."'," . "'". str_replace("'", ".", $fields[1]) . "'," . "'". str_replace("'", ".", $fields[2]) . "');"; 
$result = $conn->query($query); 
/* // commented out
if(!$result) {echo  $conn->error . "</br>";}
}else{echo $result . "</br>";}
*/};

测试2: ~7秒

enter image description here   (正如先生tadman所说,我搜索了LOAD DATA INFILE,这是超级强大的

//replace the entire loop with this simple query
$query = "LOAD DATA LOCAL INFILE'" . 
addslashes("C:\\xampp\\htdocs\\bots\\impandexp\\imports.txt")
. "' INTO TABLE imports FIELDS TERMINATED BY '\t' LINES TERMINATED BY
'\r\n'(product_hs,counteryname,units,weight,value) SET  year = '2014';";
 $result = $conn->query($query);

测试3: ~5秒 enter image description here 它与测试2相同,只是我在mr.tadman给出的同一页面上找到了有用的提示,这有助于最大化Bulk Data Loading for InnoDB Tables的速度

// turning off index checks that might slows down bulk data insertion
$query = "SET foreign_key_checks=0;";
$conn->query($query);
$query = "SET unique_checks=0;";
$conn->query($query);
$query ="SET autocommit=0;";
$conn->query($query);

$query = "LOAD DATA LOCAL INFILE'" . addslashes("C:\\xampp\\htdocs\\bots\\impandexp\\imports.txt") . "' INTO TABLE imports FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'(product_hs,counteryname,units,weight,value) SET  year = '2014';";
$result = $conn->query($query);
echo $result . "</br>";
// turning them on again
$query = "SET foreign_key_checks=1;";
$conn->query($query);
$query = "SET unique_checks=1;";
$conn->query($query);
$query ="COMMIT;";
$conn->query($query);