如何在PHP中执行多个MySQL插入

如何在PHP中执行多个MySQL插入,php,mysql,Php,Mysql,我需要在MySQL表中插入许多行(介于150到300之间),我想知道以下方法中性能更好的方法: 方法1: foreach( $persons as $person ){ $stmt = $dbLink->prepare( "INSERT INTO table SET id = :ID, name = :name,

我需要在MySQL表中插入许多行(介于150到300之间),我想知道以下方法中性能更好的方法:

方法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);

因此,在一次调用中完成您在四次调用中要完成的操作。

要回答您的问题,您应该按照以下方式组织准备/绑定/执行阶段:

//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\u EMULATE\u PREPARES=false
,则mysql只会第一次准备查询

在第一种情况下,它将为每个循环重新准备

正如其他用户所说,请记住,更好的性能改进是在for循环中只进行一次插入,而不是多次插入


编辑:如何使用参数绑定和一个查询

要使用参数绑定且仅使用一个查询,解决方案可以是:

$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 );
在循环的第一部分中,我们为每个人构建了一组占位符字符串
$placeholder
,在循环的第二部分中,我们将占位符值的绑定存储在
$parameters
数组中

在循环结束时,我们应该设置所有占位符和参数,并且可以执行查询,将
$parameters
数组传递给
execute
方法。这是使用
bindValue
/
bindParam
方法的另一种方法,但结果应相同


我认为这是使用参数绑定和只使用一个查询的唯一方法。您可以使用下面的代码来避免多个SQL调用,并在单个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(); 
//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 );
现在执行准备好的最终查询字符串

这样,查询就准备好作为字符串,您需要一次性执行它。 这将进行一次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(); 
//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在at的回答真的很有帮助。我也在这一页上认出了Moppo。

我认为这两种方法之间没有明显的区别。您正在对数据库进行相同数量的SQL调用。除了微小的差异之外,您正在运行150个单插入。使用一个查询插入150个值:(只需关注允许的最大查询大小,可能使用3个查询,每个查询50个值,或者任何最匹配的查询)您的答案生成相同数量的SQLcall@Moppo,我把我的参数绑定放在循环外,你把你的参数绑定放在循环内,它们是一样的吗?我过去认为bindParam的参数绑定应该执行一次,因为它是通过引用进行的。@StephenAdelakun:绑定应该进入循环内部,因为以前没有可用的
$person
变量。此外,对于每个具有不同参数的查询执行,应该进行不同的绑定values@Moppo,我理解您的观点,但参数绑定似乎不尊重您所指的范围。请参见此处的一些示例:了解更多关于PDO的信息。我搞错了-
PDO::ATTR\u EMULATE\u PREPARES
必须设置为
false
才能准备查询。以及要使用的单独执行。如果仿真为true,则只使用查询。无论如何,在PHP5.3.29版本上。我想我理解这一点。问题是如何将它与prepared语句一起使用。这个解决方案不会使用参数绑定。在这种情况下,使用
$stmt->query()
,而不使用prepare和execute命令也是一样的phases@Veerendra:1赞成简洁。如果有人能提供一个支持预置语句的版本,那就太好了。@StephenAdelakun:检查我答案中的编辑是否有用是的,它使用了我解释过的相同方法,但使用问号而不是命名占位符…可能我的答案至少值得投一票:)@Moppo,是的,我真的很想给你的编辑投一票,但有两个问题:@Moppo,我说你的编辑有两个问题:1<代码>如果($placeholders))将为真,无论它是否是声明的第一次迭代
$placeholders=“”
使
$placeholders
存在。我认为你应该改为使用
if(“==$placeholder)
。2.
$placeholders
的结尾将有一个尾随逗号,如果不删除尾随逗号,则查询将无效。好的,我已经在本地机器上测试了我的解决方案,然后才上线查看您的编辑。尽管如此,我还是放弃投票。但是如果你确信的话,请纠正这些问题。否:在
if($placeholders)
if(“==$placeholders)
中都会给出相同的结果:
false
。2.否:在添加当前迭代的占位符之前,在每次迭代中将逗号添加到字符串中。因此,在最后一个循环中,尾随逗号不会插入到字符串的末尾。在您的示例中,当您在占位符后添加逗号时,查询将有一个尾随逗号。您可以自己尝试验证代码that@Moppo,理解2,不确定1。我还是投赞成票。