PHP MySQL尽可能快速高效地插入1-3000行
我正在寻找使用PHP将PHP MySQL尽可能快速高效地插入1-3000行,php,mysql,performance,Php,Mysql,Performance,我正在寻找使用PHP将1-3000行插入MySQL数据库的最快方法。我目前的解决方案是用大约42秒来插入行,我认为这可能要快得多 我使用的是一个自行编写的DB类,insert()方法采用两个参数(string)$table和(array)$vars。$items数组是一个关联数组,其中键是表中的列名,值是要插入的值。这对我来说非常有效,因为我有时在一个表中有30列,并且在一个数组中已经有了数据。insert()方法如下: function insert($table,$vars) {
1-3000行插入MySQL数据库的最快方法。我目前的解决方案是用大约42秒来插入行,我认为这可能要快得多
我使用的是一个自行编写的DB类,insert()
方法采用两个参数(string)$table
和(array)$vars
。$items
数组是一个关联数组,其中键是表中的列名,值是要插入的值。这对我来说非常有效,因为我有时在一个表中有30列,并且在一个数组中已经有了数据。insert()
方法如下:
function insert($table,$vars) {
if(empty($this->sql_link)){
$this->connection();
}
$cols = array();
$vals = array();
foreach($vars as $key => $value) {
$cols[] = "`" . $key . "`";
$vals[] = "'" . $this->esc($value) . "'";
}
//join the columns and values to insert into sql
$fields = join(', ', $cols);
$values = join(', ', $vals);
$insert = mysql_query("INSERT INTO `$table` ($fields) VALUES ($values);", $this->sql_link);
return $insert;
}
它应该是不言自明的,但基本上我从$vars获取键和值,并创建一个INSERT语句。它是有效的,我认为我遇到的问题是一次发送一个查询
我应该构建一个长的查询字符串吗
在表(字段、字段2等)中插入值(1、2等);在表(字段、字段2等)中插入值(1、2等);在表(字段、字段2等)中插入值(1、2等);在表(字段、字段2等)中插入值(1、2等);在表(字段、字段2等)中插入值(1、2等)代码>并一次发送所有内容?如果是这样的话,它能在一次调用中处理3000条insert语句吗
有没有其他我看不到的方式?欢迎提供任何信息
谢谢最有效的方法是使用多行插入语法:
INSERT INTO table (field, field2, etc) VALUES (1, 2, etc),(1, 2, etc),(1, 2, etc);
:
使用VALUES语法的INSERT语句可以插入多行。为此,请包含多个列值列表,每个列值用括号括起来,并用逗号分隔。例如:
在tbl_名称中插入(a、b、c)值(1,2,3)、(4,5,6)、(7,8,9)代码>
每行的值列表必须用括号括起来
加速批量插入的标准技术,用于在事务的循环中使用准备好的SQL语句。这将使它非常理想。在那之后,你可以试着用各种方式调整它,但你可能是在浪费时间。像往常一样,这取决于;你甚至没有提到你正在使用的引擎,这是一个很大的决定因素。但我发现MySQL手册指南非常可靠
提高插入速度的两种方法:
在开始时,在插入任何之前,执行mysql\u查询(“启动事务”)
或更简单的mysql_查询(“BEGIN”)代码>。最后,执行一个mysql_查询(“提交”)代码>。这两条线路,使批量插入速度提高了5-10倍
如果表后端是MyISAM
(非InnoDB),请执行插入操作
s,后面跟着单词延迟
。例如,使用INSERT DELAYED INTO table
代替INSERT INTO table
进行传统的10-15倍加速
如果将这两种方法结合使用,则可以实现100倍的速度。自动发现插入的最大数量。
要插入这种弹药(3000),执行以下操作应该没有任何问题(假设您使用pdo):
您可以对其进行改进,使create成为一种通用的方法,为具有不同字段数量的表创建类似于上述语句的大型语句:
$fields = array("name", "id");
$fieldList = implode(", ", $fields);
$params = '(' . str_repeat('?,', count($fields) - 1) . '?)';
$values = str_repeat($params . ',', $ammountOfRows - 1) . $params;
$stmt = $dbh->prepare("INSERT INTO $table($fieldList) VALUES " . $values);
但上述解决方案的问题是,它无法处理任何行和字段数的组合
似乎mysql不仅受到行数的限制,还考虑了参数的数量
但您不希望在新的mysql版本更改参数、行甚至sql语句大小的限制时更改代码
因此,创建生成大型语句的通用方法的更好方法是尝试使用底层数据库引擎:
/**
* Creates an insert sql with the maximum allowed of parameters
* @param string $table
* @param string $attributeList
* @param int &$ammountInserts returns the ammount of inserts
* @return \PDOStatement
*/
public static function getBiggestInsertStatement($table, $attributeList, $max, &$ammountInserts)
{
$previousSize = null;
$size = 10;
$sql = 'INSERT INTO ' . $table . '(' . implode(',', $attributeList) . ') values ';
$return = null;
$params = '(' . str_repeat('?,', count($attributeList) - 1) . '?)';
do {
try {
$previousSize = $size;
$values = str_repeat($params . ',', $size - 1) . $params;
$return = Db::getInstance()->prepare($sql . $values);
if ($size > $max) {
$values = str_repeat($params . ',', $max - 1) . $params;
$return = Db::getInstance()->prepare($sql . $values);
$ammountInserts = $max;
break;
}
$ammountInserts = $size;
$size *= 2;
} catch(\Exception $e) {
}
} while($previousSize != $size);
return $return;
}
您必须记住的一件事是,由于您不知道限制,因此查询可以推送较低数量的项,而这些项都是您需要插入的
因此,您必须创建一个如下所示的策略,以成功实现在任何可能的场景中插入所有这些策略:
$insert = Db::getBiggestInsertStatement($table, array('field1','field2'), $numrows, $maximumInserts);
$i = 0;
$values = array();
for ($j = 0; $j < $numrows; $j++) {
if ($i === $maximumInserts) {
$insert->execute($values);
$i = 0;
$values = array();
}
$values[] = "value1" . $j;
$values[] = "value2" . $j;
$i++;
});
if ($i > 0) {
$insertRemaining = Db::getBiggestInsertStatement($table, array('field1', 'field2'), $i, $maximumInserts);
$insertRemaining->execute($values);
}
$insert=Db::getBiggestInsertStatement($table,array('field1','field2'),$numrows,$maximumInserts);
$i=0;
$values=array();
对于($j=0;$j<$numrows;$j++){
如果($i===$MaximumInsert){
$insert->execute($values);
$i=0;
$values=array();
}
$values[]=“value1”。$j;
$values[]=“value2”。$j;
$i++;
});
如果($i>0){
$insertRemaining=Db::getBiggestInsertStatement($table,array('field1','field2'),$i,$maximumInserts);
$insertRemaining->execute($value);
}
我曾尝试在一个表中插入一列1000000行,插入只需几秒钟,再加上几分钟就完成了。Mysql可以直接从文件导入数据,这可以显著加快导入数据的速度。见:
作为评论添加,因为这是一个轶事:我在我的一个网站上遇到了同样的问题,我想一次插入50行。使用这种语法将插入所有50个的时间减少了大约250倍。太好了,这就是我所说的我遗漏的东西!感谢除了MySQL本身能够处理的之外,没有其他合理的限制。对于任何不以百万为单位的数字,不要担心:P+1
是好的建议。注意:PHP不鼓励使用mysql\uuz
函数,请使用MySQLi
或PDO
。我正在解析大型xml文件并进行数千次插入。在我的情况下,正好是x4速度在mariaDB/InnoDB上启动事务时的速度
$insert = Db::getBiggestInsertStatement($table, array('field1','field2'), $numrows, $maximumInserts);
$i = 0;
$values = array();
for ($j = 0; $j < $numrows; $j++) {
if ($i === $maximumInserts) {
$insert->execute($values);
$i = 0;
$values = array();
}
$values[] = "value1" . $j;
$values[] = "value2" . $j;
$i++;
});
if ($i > 0) {
$insertRemaining = Db::getBiggestInsertStatement($table, array('field1', 'field2'), $i, $maximumInserts);
$insertRemaining->execute($values);
}