Przekazuję duży zestaw danych do tabeli MySQL za pośrednictwem PHP za pomocą poleceń wstawiania i zastanawiam się, czy można wstawić około 1000 wierszy na raz za pomocą zapytania innego niż dołączanie każdej wartości na końcu ciągu o długości mili, a następnie wykonanie go. Używam frameworka CodeIgniter, więc jego funkcje są również dostępne dla mnie.
php
mysql
codeigniter
insert
bulkinsert
toofarsideways
źródło
źródło
Odpowiedzi:
Składanie jednej
INSERT
instrukcji z wieloma wierszami jest znacznie szybsze w MySQL niż jednejINSERT
instrukcji na wiersz.To powiedziawszy, wygląda na to, że możesz mieć problemy z obsługą ciągów znaków w PHP, co jest tak naprawdę problemem algorytmu, a nie języka. Zasadniczo podczas pracy z dużymi ciągami znaków chcesz zminimalizować niepotrzebne kopiowanie. Przede wszystkim oznacza to, że chcesz uniknąć konkatenacji. Najszybszym i najbardziej wydajnym pod względem pamięci sposobem zbudowania dużego ciągu, na przykład wstawiania setek wierszy w jednym, jest wykorzystanie
implode()
funkcji i przypisania tablicy.$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));
Zaletą tego podejścia jest to, że nie kopiujesz i nie kopiujesz ponownie instrukcji SQL, które do tej pory składałeś przy każdym konkatenacji; zamiast tego PHP robi to raz w
implode()
instrukcji. To wielka wygrana.Jeśli masz wiele kolumn do złożenia, a jedna lub więcej jest bardzo długich, możesz również zbudować wewnętrzną pętlę, aby zrobić to samo i użyć
implode()
do przypisania klauzuli value do tablicy zewnętrznej.źródło
mysql_real_escape_string
zmysqli_real_escape_string
imysql_query
zmysqli_query
jak używam mysqli i zostały one przestarzałe jak z PHP5. Wielkie dzięki!mysql_*
został usunięty z PHP, więc upewnij się, że korzystasz zmysqli_*
interfejsu.Codeigniter obsługuje teraz wielokrotne wstawianie / wstawianie partii. Miałem ten sam problem. Chociaż jest już bardzo późno na odpowiedź, to komuś pomoże. Dlatego odpowiadając na to pytanie.
$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')
źródło
Możesz przygotować zapytanie do wstawienia jednego wiersza za pomocą klasy mysqli_stmt, a następnie iterować po tablicy danych. Coś jak:
$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();
Gdzie „idsb” to typy danych, które wiążesz (int, double, string, blob).
źródło
Wiem, że to stare zapytanie, ale właśnie czytałem i pomyślałem, że dodam to, co znalazłem gdzie indziej:
mysqli w PHP 5 to ojbect z kilkoma dobrymi funkcjami, które pozwolą Ci przyspieszyć czas wstawiania odpowiedzi powyżej:
$mysqli->autocommit(FALSE); $mysqli->multi_query($sqlCombined); $mysqli->autocommit(TRUE);
Wyłączenie autocommit podczas wstawiania wielu wierszy znacznie przyspiesza wstawianie, więc wyłącz je, a następnie wykonaj, jak wspomniano powyżej, lub po prostu utwórz ciąg (sqlCombined), który składa się z wielu instrukcji wstawiania oddzielonych średnikami i wielu zapytań poradzi sobie z nimi dobrze.
Mam nadzieję, że pomoże to komuś zaoszczędzić czas (wyszukiwanie i wstawianie!)
R
źródło
Zawsze możesz użyć mysql
LOAD DATA
:LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'
do zbiorczego wstawiania zamiast używania zestawu
INSERT
instrukcji.źródło
LOCAL
bit.Cóż, nie chcesz wykonywać 1000 zapytań, ale zrobienie tego jest w porządku:
$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);
W zależności od źródła danych wypełnienie tablicy może być tak proste, jak otwarcie pliku i zrzucenie zawartości do tablicy za pośrednictwem
file()
.źródło
$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));
źródło
Możesz to zrobić na kilka sposobów w Codeigniter np
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));
źródło
Chociaż na to pytanie jest już za późno. Oto moja odpowiedź na to samo.
Jeśli używasz CodeIgniter, możesz użyć wbudowanych metod zdefiniowanych w klasie query_builder.
$ this-> db-> insert_batch ()
Generuje ciąg wstawiania na podstawie dostarczonych danych i uruchamia zapytanie. Do funkcji można przekazać tablicę lub obiekt. Oto przykład wykorzystujący tablicę:
$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')
Pierwszy parametr będzie zawierał nazwę tabeli, drugi to asocjacyjna tablica wartości.
Więcej informacji na temat query_builder można znaleźć tutaj
źródło
Stworzyłem klasę wykonującą wieloliniowość, która jest używana w następujący sposób:
$pdo->beginTransaction(); $pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10); $pmi->insertRow($data); // .... $pmi->insertRow($data); $pmi->purgeRemainingInserts(); $pdo->commit();
gdzie klasa jest zdefiniowana w następujący sposób:
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; } }
źródło
Aby wstawić wiele wierszy danych, użyj wstawiania wsadu do zapłonnika kodu.
$this->db->insert_batch('tabname',$data_array); // $data_array holds the value to be inserted
źródło
Stworzyłem tę prostą funkcję, z której możecie z łatwością korzystać. Będziesz musiał przekazać nazwę
($tbl)
tabeli, pole tabeli($insertFieldsArr)
z danymi wstawiającymi, tablicą danych($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)); }
źródło