вставьте несколько строк через массив PHP в MySQL

Я передаю большой набор данных в таблицу MySQL через PHP с помощью команд вставки, и мне интересно, возможно ли вставлять примерно 1000 строк за один раз с помощью запроса, отличного от добавления каждого значения в конец строки длиной в милю, а затем выполняя это. Я использую каркас CodeIgniter, поэтому его функции также доступны для меня.

121

Решение

Сборка одного 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 ​​внешнему массиву.

218

Другие решения

Многократная вставка / пакетная вставка теперь поддерживается 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')
58

Вы можете подготовить запрос для вставки одной строки с помощью класса 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).

19

Я знаю, что это старый запрос, но я просто читал и думал, что добавлю то, что нашел в другом месте:

mysqli в PHP 5 — это объект с некоторыми хорошими функциями, которые позволят вам ускорить вставку ответа выше:

$mysqli->autocommit(FALSE);
$mysqli->multi_query($sqlCombined);
$mysqli->autocommit(TRUE);

Отключение автоматической фиксации при вставке множества строк значительно ускоряет вставку, поэтому отключите ее, затем выполните, как указано выше, или просто создайте строку (sqlCombined), которая состоит из множества операторов вставки, разделенных точками с запятой, и мультизапрос прекрасно с ними справится.

Надеюсь, что это поможет кому-то сэкономить время (поиск и вставка!)

р

14

Вы всегда можете использовать 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 заявления.

7

Ну, вы не хотите выполнять 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(),

5
$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));
3

Я создал класс, который выполняет многострочный, который используется следующим образом:

$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;
}
}
0