У меня есть скрипт, который вставляет много данных. Эти данные в основном являются копией предыдущей вставки, однако, по крайней мере, одно значение отличается. Поэтому я готовлю заявление и связываю параметры для выполнения и повторения.
Тем не менее, я попытался записать это на подготовленную пакетную вставку, вставляя по 1000 рядов одновременно. К сожалению, я не могу заставить его работать. Код, который я использую сейчас, просто вставляет все данные сразу. Однако это нежелательно, поскольку объем данных может быть намного больше, чем проверено.
Код, который я сейчас использую (массовая вставка сразу):
$Data = array(
array("1", "2", "3", "4"),
array("1", "2", "3", "5"),
array("1", "2", "3", "6"),
array("1", "2", "3", "7"),
array("1", "2", "3", "8"),
//ETC
);
//AS YOU CAN SEE, ONLY COL4 CHANGES
$sql = $mysqli->prepare("INSERT INTO `Table` (Col1, Col2, Col3, Col4) VALUES ".implode(', ', array_fill(0, count($Data), "(?, ?, ?, ?)")));
foreach ($Data as $InsertData) {
$sql->bind_param('iiii', $InsertData[0], $InsertData[1], $InsertData[2], $InsertData[3]);
}
$sql->execute();
Я хочу добиться того, чтобы данные были вставлены с подготовленным утверждением, как указано выше, но с лимит 1000 (или любое другое число) на партию. Я не могу заставить это работать. Я пытался использовать array_splice
и другие методы, но я не мог заставить его работать.
Вместо того, чтобы пытаться добавить больше копий массива, вы можете использовать простые циклы for для работы в сегментах:
$arraySize = count($Data);
for ( $i = 0; $i < $arraySize; $i+=1000 ) {
// Number of elements in this chunk
$thisChunk = min(1000, $arraySize-$i);
// Prepare your statement
$sql = $mysqli->prepare("INSERT INTO `Table` (Col1, Col2, Col3, Col4) VALUES ".implode(', ', array_fill(0, $thisChunk, "(?, ?, ?, ?)")));
for( $j = $i; $i < $i + $thisChunk; $j++ ) {
// Bind this data from $Data[$j]
}
}
Это, конечно, будет каждый раз заново подготавливать ваше утверждение, вы можете избежать этого, если знаете, что thisChunk имеет длину 1000 элементов.
Вы должны рассмотреть возможность использования LOAD DATA INFILE.
Вероятно, это будет намного быстрее, чем использование INSERT с пакетами строк, даже если вам сначала нужно записать временный файл.
$Data = array(
array("1", "2", "3", "4"),
array("1", "2", "3", "5"),
array("1", "2", "3", "6"),
array("1", "2", "3", "7"),
array("1", "2", "3", "8"),
//ETC
);
$tempname = tempnam("/tmp", "data");
$fp = fopen($tempname, "w");
foreach ($Data as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
if ($mysqli->query("LOAD DATA INFILE '$tempname' INTO TABLE `Table`
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"'
") === false) {
error_log($mysqli->error);
}
unlink($tempname);
Читать https://dev.mysql.com/doc/refman/5.7/en/load-data.html чтобы убедиться, что вы понимаете о LOCAL
вариант и local_infile
а также secure_file_priv
параметры конфигурации.