如何优化此 sql 插入 php 代码?
how to optimize this sql insertion php code?
我有 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"
文本reader视图:
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
-数据库有3个table是这样的:
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 代码 是这样的
$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>";
}
};
起初我以为是索引问题导致插入变慢,所以我把"imports"table中的所有索引都去掉了,但是并没有变快!!
是数据库设计的问题还是我的 php 代码的问题?
另请注意,浏览器在前 5 分钟通知 "waiting for response from the server",然后大部分剩余时间通知 "transferring data from server",这是因为响应 html 行计数器 1:1 </br> 2:1 </br> .....
有超过 40'000 行(在 php 代码中声明)?
请考虑我是新手,谢谢。
非常感谢tadman and Hanlet Escaño and Uueerdo and Julie Pelletier and Solarflare
在评论中帮助我。
我使用您在评论中建议的方法对 PHP 代码进行了 3 处不同的更改,然后我测试了结果,这里是测试结果。
3 次测试的结论: 正如 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 相同,只是我在 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);
我有 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"
文本reader视图:
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
-数据库有3个table是这样的:
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 代码 是这样的
$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>";
}
};
起初我以为是索引问题导致插入变慢,所以我把"imports"table中的所有索引都去掉了,但是并没有变快!! 是数据库设计的问题还是我的 php 代码的问题?
另请注意,浏览器在前 5 分钟通知 "waiting for response from the server",然后大部分剩余时间通知 "transferring data from server",这是因为响应 html 行计数器 1:1 </br> 2:1 </br> .....
有超过 40'000 行(在 php 代码中声明)?
请考虑我是新手,谢谢。
非常感谢tadman and Hanlet Escaño and Uueerdo and Julie Pelletier and Solarflare 在评论中帮助我。
我使用您在评论中建议的方法对 PHP 代码进行了 3 处不同的更改,然后我测试了结果,这里是测试结果。
3 次测试的结论: 正如 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 相同,只是我在 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);