Мне нужно вставить много строк (от 150 до 300) в таблицу MySQL, и я хочу лучше знать следующие подходы в отношении производительности:
Подход 1:
foreach( $persons as $person ){ $stmt = $dbLink->prepare( "INSERT INTO table SET id = :ID, name = :name, email = :email, mobile = :mobile"); $stmt->execute( array( ':ID'=>$person->getID(), ':name'=>$person->getName(), ':email'=>$person->getEmail(), ':mobile'=>$person->getMobile(), ) ); }
Подход 2:
$stmt = $dbLink->prepare( "INSERT INTO table SET id = :ID, name = :name, email = :email, mobile = :mobile"); $stmt->bindParam( ':ID', $person->getID(), PDO::PARAM_STR ); $stmt->bindParam( ':name', $person->getName(), PDO::PARAM_STR ); $stmt->bindParam( ':email', $person->getEmail(), PDO::PARAM_STR ); $stmt->bindParam( ':mobile', $person->getMobile(), PDO::PARAM_STR ); foreach( $persons as $person ){ $stmt->execute(); }
Это количество звонков в базу данных, что отличает. Уменьшите количество звонков как можно больше.
Вместо этого:
insert (a,b,c) values (d,e,f); insert (a,b,c) values (g,h,i); insert (a,b,c) values (j,k,l); insert (a,b,c) values (m,n,o);
сделай это:
insert (a,b,c) values (d,e,f),(g,h,i),(j,k,l),(m,n,o);
Таким образом, сделав одним звоном то, что вы бы сделали в 4 вызовах.
Вы можете использовать приведенный ниже код, чтобы избежать множественных вызовов SQL и вставить данные в вызов Single SQL
$first_string = "INSERT INTO table (id, name, email,mobile) VALUES ";//Basic query foreach( $persons as $person ) { $first_string .="(".$person->getID().",".$person->getName().",".$person->getEmail().",".$person->getMobile()."),";//Prepare the values } $final_query_string = substr($first_string, 0,-1);// This will remove the extra , at the end of the string $stmt = $dbLink->prepare($final_query_string); $stmt->execute();
Теперь запустите готовую строку запроса.
Таким образом, запрос готов в виде строки, и вам нужно выполнить его за один раз. Это сделает один вызов SQL
Чтобы ответить на ваш вопрос, так вы должны структурировать фазы подготовки / привязки / выполнения:
//prepare the query only the first time $stmt = $dbLink->prepare( "INSERT table (id, name, email, mobile) VALUES (:ID, :name, :email, :mobile)" ); //bind params and execute for every person foreach( $persons as $person ){ $stmt->bindValue( ':ID', $person->getID(), PDO::PARAM_STR ); $stmt->bindValue( ':name', $person->getName(), PDO::PARAM_STR ); $stmt->bindValue( ':email', $person->getEmail(), PDO::PARAM_STR ); $stmt->bindValue( ':mobile', $person->getMobile(), PDO::PARAM_STR ); $stmt->execute(); }
Если у вас есть PDO::ATTR_EMULATE_PREPARES = false
, запрос будет подготовлен mysql только в первый раз.
В первом случае он будет переработан для каждого цикла цикла
Как правильно говорят другие пользователи, помните, что лучшим улучшением производительности было бы сделать ТОЛЬКО одну вставку вместо многих вставок в цикл for
EDIT: как использовать привязки параметров и один запрос
Для использования привязки параметров и только одного запроса решение может быть:
$placeholders = ""; //this will be filled with placeholders : ( :id_1, :name_1, :email_1, :mobile_1),( :id_2 ... ) $parameters = array(); //this will keep the parameters bindings $i = 1; foreach( $persons as $person ) { //add comma if not first iteration if ( $placeholders ) $placeholders .= ", "; //build the placeholders string for this person $placeholders .= "( :id_$i, :name_$i, :email_$i, :mobile_$i )"; //add parameters for this person $parameters[":id_$i"] = $person->getID(); $parameters[":name_$i"] = $person->getName(); $parameters[":email_$i"] = $person->getEmail(); $parameters[":mobile_$i"] = $person->getMobile(); $i++; } //build the query $stmt = $dbLink->prepare( "INSERT INTO table (id, name, email, mobile) VALUES " . $placeholders ); //execute the query passing parameters $stmt->execute( $parameters );
В первой части цикла мы строим строку $placeholders
с набором заполнителей для каждого человека, во второй части цикла мы сохраняем привязки значений заполнителей в массиве $parameters
В конце цикла мы должны установить все заполнители и параметры, и мы можем выполнить запрос, передающий массив $parameters
в метод execute
. Это альтернативный способ использования методов bindValue
/ bindParam
но результат должен быть таким же
Я думаю, что это единственный способ использовать привязки параметров и использовать только один запрос
//declare array of values to be passed into PDO::Statemenet::execute() $values = array(); //prepare sql string $sql = 'INSERT INTO students ( id, name, email, mobile ) VALUES '; foreach( $students as $student ){ $sql .= '( ?, ?, ?, ? ),'; //concatenate placeholders with sql string //generate array of values and merge with previous values $values = array_merge( $values, array( $student->getID(), $student->getName(), $student->getEmail(), $student->getMobile(), ) ); } $sql = rtrim( $sql, ',' ); //remove the trailing comma (,) and replace the sql string $stmt = $this->dbLink->prepare( $sql ); $stmt->execute( $values );
-//declare array of values to be passed into PDO::Statemenet::execute() $values = array(); //prepare sql string $sql = 'INSERT INTO students ( id, name, email, mobile ) VALUES '; foreach( $students as $student ){ $sql .= '( ?, ?, ?, ? ),'; //concatenate placeholders with sql string //generate array of values and merge with previous values $values = array_merge( $values, array( $student->getID(), $student->getName(), $student->getEmail(), $student->getMobile(), ) ); } $sql = rtrim( $sql, ',' ); //remove the trailing comma (,) and replace the sql string $stmt = $this->dbLink->prepare( $sql ); $stmt->execute( $values );
-//declare array of values to be passed into PDO::Statemenet::execute() $values = array(); //prepare sql string $sql = 'INSERT INTO students ( id, name, email, mobile ) VALUES '; foreach( $students as $student ){ $sql .= '( ?, ?, ?, ? ),'; //concatenate placeholders with sql string //generate array of values and merge with previous values $values = array_merge( $values, array( $student->getID(), $student->getName(), $student->getEmail(), $student->getMobile(), ) ); } $sql = rtrim( $sql, ',' ); //remove the trailing comma (,) and replace the sql string $stmt = $this->dbLink->prepare( $sql ); $stmt->execute( $values );
-//declare array of values to be passed into PDO::Statemenet::execute() $values = array(); //prepare sql string $sql = 'INSERT INTO students ( id, name, email, mobile ) VALUES '; foreach( $students as $student ){ $sql .= '( ?, ?, ?, ? ),'; //concatenate placeholders with sql string //generate array of values and merge with previous values $values = array_merge( $values, array( $student->getID(), $student->getName(), $student->getEmail(), $student->getMobile(), ) ); } $sql = rtrim( $sql, ',' ); //remove the trailing comma (,) and replace the sql string $stmt = $this->dbLink->prepare( $sql ); $stmt->execute( $values );
Полные кредиты всем, кто вдохновил меня на это решение. Это кажется кратким и ясным:
В частности, ответ JM4 на PDO Prepared Вставляет несколько строк в одном запросе . Я также признаю Moppo на этой странице.