我有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代码中声明)?
请考虑我是新手,谢谢。
答案 0 :(得分:2)
非常感谢mr.tadman和mr.Hanlet Escaño以及mr.Uueerdo和mr.Julie Pelletier以及mr.Solarflare 在评论中帮助我。
我使用您在评论中建议的方法对我的PHP代码进行了3次不同的更改,然后我测试了结果,这里是测试结果。
3次测试的结论:正如mr.tadman建议的那样,关键在于LOAD DATA INFILE。它将执行时间大大缩短到不到7秒,这是3次测试。
原始代码: ~26分钟
测试1: ~34分钟
(正如先生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秒
(正如先生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秒
它与测试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);