我正在使用插入命令通过PHP将大型数据集传递到MySQL表中,并且我想知道是否有可能通过查询而不是将每个值附加到一英里长的字符串的末尾一次插入大约1000行,然后执行它。我正在使用CodeIgniter框架,因此我也可以使用它的功能。
我正在使用插入命令通过PHP将大型数据集传递到MySQL表中,并且我想知道是否有可能通过查询而不是将每个值附加到一英里长的字符串的末尾一次插入大约1000行,然后执行它。我正在使用CodeIgniter框架,因此我也可以使用它的功能。
Answers:
INSERT
在MySQL中,用多行汇编一条语句要比一条语句快得多INSERT
每行语句。
也就是说,听起来您可能会遇到PHP中的字符串处理问题,这实际上是算法问题,而不是语言问题。基本上,在处理大字符串时,您希望最大程度地减少不必要的复制。首先,这意味着您要避免串联。构建大型字符串(例如一次插入数百行)的最快,最节省内存的方法是利用implode()
函数和数组分配。
$sql = array();
foreach( $data as $row ) {
$sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));
这种方法的优点是,您无需复制和重新复制到目前为止已与每个串联组合的SQL语句。相反,PHP 在语句中执行一次implode()
。这是一个巨大的胜利。
如果您有很多列要放在一起,并且一个或多个列很长,则还可以构建一个内部循环以执行相同的操作,并使用implode()
将values子句分配给外部数组。
mysql_real_escape_string
与mysqli_real_escape_string
并mysql_query
用mysqli_query
,因为我用的MySQLi而这些都被弃用PHP5的。非常感谢!
mysql_*
已从PHP中删除,因此请确保使用该mysqli_*
接口。
现在,codeigniter支持多次插入/批量插入。我有同样的问题。尽管回答问题已经很晚了,但是它将对某人有所帮助。这就是为什么回答这个问题。
$data = array(
array(
'title' => 'My title' ,
'name' => 'My Name' ,
'date' => 'My date'
),
array(
'title' => 'Another title' ,
'name' => 'Another Name' ,
'date' => 'Another date'
)
);
$this->db->insert_batch('mytable', $data);
// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')
您可以使用mysqli_stmt类准备查询以插入一行,然后遍历数据数组。就像是:
$stmt = $db->stmt_init();
$stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)");
foreach($myarray as $row)
{
$stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']);
$stmt->execute();
}
$stmt->close();
其中“ idsb”是要绑定的数据类型(int,double,string,blob)。
我知道这是一个旧查询,但是我只是在阅读并认为我会添加在其他地方找到的内容:
PHP 5中的mysqli是一个具有一些好的功能的对象,它将使您加快以上答案的插入时间:
$mysqli->autocommit(FALSE);
$mysqli->multi_query($sqlCombined);
$mysqli->autocommit(TRUE);
在插入许多行时关闭自动提交可以大大加快插入速度,因此请关闭它,然后按如上所述执行,或者仅创建一个字符串(sqlCombined),该字符串包含许多用分号和多查询分隔的插入语句,可以很好地处理它们。
希望这可以帮助某人节省时间(搜索和插入!)
[R
您可以始终使用mysql的LOAD DATA
:
LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'
进行批量插入,而不是使用一堆INSERT
语句。
LOCAL
位。
好吧,您不想执行1000个查询调用,但是可以这样做:
$stmt= array( 'array of statements' );
$query= 'INSERT INTO yourtable (col1,col2,col3) VALUES ';
foreach( $stmt AS $k => $v ) {
$query.= '(' .$v. ')'; // NOTE: you'll have to change to suit
if ( $k !== sizeof($stmt)-1 ) $query.= ', ';
}
$r= mysql_query($query);
根据您的数据源,填充数组可能就像打开文件并将内容通过转储到数组中一样容易file()
。
$query= array();
foreach( $your_data as $row ) {
$query[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $query));
您可以在codeigniter中使用多种方法来实现,例如
第一次循环
foreach($myarray as $row)
{
$data = array("first"=>$row->first,"second"=>$row->sec);
$this->db->insert('table_name',$data);
}
第二 -按插入批次
$data = array(
array(
'first' => $myarray[0]['first'] ,
'second' => $myarray[0]['sec'],
),
array(
'first' => $myarray[1]['first'] ,
'second' => $myarray[1]['sec'],
),
);
$this->db->insert_batch('table_name', $data);
第三种方式-通过多值传递
$sql = array();
foreach( $myarray as $row ) {
$sql[] = '("'.mysql_real_escape_string($row['first']).'", '.$row['sec'].')';
}
mysql_query('INSERT INTO table (first, second) VALUES '.implode(',', $sql));
尽管现在回答这个问题为时已晚。这是我对同样的答案。
如果使用的是CodeIgniter,则可以使用在query_builder类中定义的内置方法。
$ this-> db-> insert_batch()
根据您提供的数据生成一个插入字符串,然后运行查询。您可以将数组或对象传递给函数。这是使用数组的示例:
$data = array(
array(
'title' => 'My title',
'name' => 'My Name',
'date' => 'My date'
),
array(
'title' => 'Another title',
'name' => 'Another Name',
'date' => 'Another date'
)
);
$this->db->insert_batch('mytable', $data);
// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')
第一个参数将包含表名称,第二个参数是值的关联数组。
您可以在此处找到有关query_builder的更多详细信息
我创建了一个执行多行的类,该类的用法如下:
$pdo->beginTransaction();
$pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10);
$pmi->insertRow($data);
// ....
$pmi->insertRow($data);
$pmi->purgeRemainingInserts();
$pdo->commit();
该类的定义如下:
class PDOMultiLineInserter {
private $_purgeAtCount;
private $_bigInsertQuery, $_singleInsertQuery;
private $_currentlyInsertingRows = array();
private $_currentlyInsertingCount = 0;
private $_numberOfFields;
private $_error;
private $_insertCount = 0;
/**
* Create a PDOMultiLine Insert object.
*
* @param PDO $pdo The PDO connection
* @param type $tableName The table name
* @param type $fieldsAsArray An array of the fields being inserted
* @param type $bigInsertCount How many rows to collect before performing an insert.
*/
function __construct(PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
$this->_numberOfFields = count($fieldsAsArray);
$insertIntoPortion = "REPLACE INTO `$tableName` (`".implode("`,`", $fieldsAsArray)."`) VALUES";
$questionMarks = " (?".str_repeat(",?", $this->_numberOfFields - 1).")";
$this->_purgeAtCount = $bigInsertCount;
$this->_bigInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks.str_repeat(", ".$questionMarks, $bigInsertCount - 1));
$this->_singleInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks);
}
function insertRow($rowData) {
// @todo Compare speed
// $this->_currentlyInsertingRows = array_merge($this->_currentlyInsertingRows, $rowData);
foreach($rowData as $v) array_push($this->_currentlyInsertingRows, $v);
//
if (++$this->_currentlyInsertingCount == $this->_purgeAtCount) {
if ($this->_bigInsertQuery->execute($this->_currentlyInsertingRows) === FALSE) {
$this->_error = "Failed to perform a multi-insert (after {$this->_insertCount} inserts), the following errors occurred:".implode('<br/>', $this->_bigInsertQuery->errorInfo());
return false;
}
$this->_insertCount++;
$this->_currentlyInsertingCount = 0;
$this->_currentlyInsertingRows = array();
}
return true;
}
function purgeRemainingInserts() {
while ($this->_currentlyInsertingCount > 0) {
$singleInsertData = array();
// @todo Compare speed - http://www.evardsson.com/blog/2010/02/05/comparing-php-array_shift-to-array_pop/
// for ($i = 0; $i < $this->_numberOfFields; $i++) $singleInsertData[] = array_pop($this->_currentlyInsertingRows); array_reverse($singleInsertData);
for ($i = 0; $i < $this->_numberOfFields; $i++) array_unshift($singleInsertData, array_pop($this->_currentlyInsertingRows));
if ($this->_singleInsertQuery->execute($singleInsertData) === FALSE) {
$this->_error = "Failed to perform a small-insert (whilst purging the remaining rows; the following errors occurred:".implode('<br/>', $this->_singleInsertQuery->errorInfo());
return false;
}
$this->_currentlyInsertingCount--;
}
}
public function getError() {
return $this->_error;
}
}
我创建了一个简单的函数,你们可以轻松使用。您将需要针对插入的数据data array 传递table-name ($tbl)
和table-field 。($insertFieldsArr)
($arr)
insert_batch('table',array('field1','field2'),$dataArray);
function insert_batch($tbl,$insertFieldsArr,$arr){ $sql = array();
foreach( $arr as $row ) {
$strVals='';
$cnt=0;
foreach($insertFieldsArr as $key=>$val){
if(is_array($row)){
$strVals.="'".mysql_real_escape_string($row[$cnt]).'\',';
}
else{
$strVals.="'".mysql_real_escape_string($row).'\',';
}
$cnt++;
}
$strVals=rtrim($strVals,',');
$sql[] = '('.$strVals.')';
}
$fields=implode(',',$insertFieldsArr);
mysql_query('INSERT INTO `'.$tbl.'` ('.$fields.') VALUES '.implode(',', $sql));
}