2

目前我将准备好的语句保存到一个私有变量中,因为我忽略了它们在深度中的实际工作方式,以防万一。

所以这个问题真的很简单,如果我迭代相同的$PDO->prepare(),它会再次准备相同的查询吗?

foreach( $arr as $docid ) {
  if( $this->dbLink === null ) { // PDO resource, saved in the object.
     throw new Exception( 'Must first connect to DB' );
  }
  if( $this->queryCheckAccess === null ) {
    $query = 'SELECT * from something where id = :id';
    $this->queryCheckAccess = $this->dbLink->prepare($query);
  }
  else {
    $result = $this->queryCheckAccess->execute(array(':id'=>$docid));
  }
}

有关系吗?或者数据库引擎/PHP 足够聪明,知道它是同一个准备好的语句?

非常感谢。

- - - - - - - - - 编辑 - - - - - - -

我想我被误解了。

我要问的是如果我这样做会发生什么:

$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);

如果我这样做会发生什么:

if( $this->queryCheckAccess === null ) {
  $query = 'SELECT * from something where id = :id';
  $this->queryCheckAccess = $this->dbLink->prepare($query);
}

引擎会在第一个示例中准备 4 次查询吗?或者会注意到它是同一个查询并且只是“跳转”那个?

4

4 回答 4

2

您的代码只准备一次查询,因为在第一次循环迭代之后,它不是 NULL,因此条件块不会运行。但是每次循环检查条件是浪费时间。

但是要回答您的问题,如果您 p​​repare() 相同的查询,它确实会做多余的工作,即使该查询与您之前准备的查询相同。所以你应该避免这种情况。

但是您根本不需要在循环内部进行准备。在开始循环之前准备一次,并将变量绑定到参数。您不需要每次都在循环中绑定,只需更改该变量的值即可。

if( $this->dbLink === null ) { // PDO resource, saved in the object.
    throw new Exception( 'Must first connect to DB' );
}
$query = 'SELECT * from something where id = :id';
$this->queryCheckAccess = $this->dbLink->prepare($query);
$this->queryCheckAccess->bindParam(':id' => $docidparam);
foreach( $arr as $docid ) {
    $docidparam = $docid;
    $result = $this->queryCheckAccess->execute();
}

我不确定您是否可以绑定变量并将其用作循环变量,可能存在范围冲突。

此查询的另一个建议:为什么不只运行一个查询来搜索值列表?

$list = implode(",", array_fill(1, count($arr), "?"));
$query = "SELECT * FROM something WHERE id IN ( $list )";
$this->queryCheckAccess = $this->dbLink->prepare($query);
$this->queryCheckAccess->execute($arr);

PS:你也应该检查错误。如果启用 PDO 错误模式 EXCEPTION,那么错误会自动抛出异常。如果不启用该模式,则需要检查 prepare() 和 execute() 的返回值,如果有错误则返回false 。

于 2013-09-25T23:10:38.197 回答
0

我只是运行类似于您的示例的代码,并启用MySQL Query LOG我发现所有准备请求都发送到 MySQL 服务器

   Prepare  SELECT * FROM test_table WHERE username = ?
   Close stmt   
   Prepare  SELECT * FROM test_table WHERE username = ?
   Close stmt   
   Prepare  SELECT * FROM test_table WHERE username = ?
   Close stmt   
   Prepare  SELECT * FROM test_table WHERE username = ?
   Close stmt

测试代码:

$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth = $dbh->prepare($sql);
$sth->bindParam(1, $user);
$sth->execute();

那么,最好的办法就是准备一次,然后绑定不同的值再执行。

$sth = $dbh->prepare($sql);
$user = "test";
$sth->bindParam(1, $user);
$sth->execute();

$user = "test2";
$sth->bindParam(1, $user);
$sth->execute();

$user = "test";
$sth->bindParam(1, $user);
$sth->execute();
于 2013-09-25T20:53:31.730 回答
-1

不,这是准备好的语句的主要特征之一。如果您要多次运行相同的查询但使用不同的变量,那么准备查询将使您的速度提高。特别是如果您使用事务(需要 InnoDB 存储引擎)。

于 2013-09-25T20:21:39.550 回答
-1
  • 要回答标题中的问题(这与正文中的问题完全不同),避免多次准备相同语句的最佳方法显然是避免运行多个类似的查询

  • 要从问题正文中回答问题 - 不,DB Engine / PHP 不够“聪明”,无法知道再次准备了相同的查询。每次新的 prepare() 调用都会创建另一个语句。我会首先讨厌这种“聪明”的行为。你的工具越“聪明”,你得到的结果就越不可预测。

  • 为了回答代码中的真正问题,聪明的开发人员会使用正确的工具来为自己省去麻烦。
    使用safeMysql整个混乱将减少到一个查询和一行代码

    $data = $this->dbLink->getAll('SELECT * from somth where id IN (?a)', $arr);
    

    S0 - 没有多个查询,没有多个准备,没有多个问题。

顺便说一句,您的代码正在丢失第一个 ID。但是,如果您不使用结果,您将失去所有这些,但最后一个。

于 2013-09-26T06:14:17.663 回答