目前我将准备好的语句保存到一个私有变量中,因为我忽略了它们在深度中的实际工作方式,并以防万一。
所以问题真的很简单,如果我迭代相同的$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 次?或者会注意到它是相同的查询并"跳跃"它?
您的代码只准备一次查询,因为在第一次循环迭代之后,它不是 NULL,因此条件块不会运行。但是每次通过循环检查条件都是浪费时间。
但是要回答您的问题,如果您准备((相同的查询,它确实会做多余的工作,即使该查询与您之前准备的查询相同。所以你应该避免这种情况。
但是您根本不需要在循环内准备。在开始循环之前准备一次,并将变量绑定到参数。您不需要每次在循环中绑定,只需更改该变量的值即可。
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 错误模式异常,则错误将自动引发异常。如果不启用该模式,则需要检查 prepare(( 和 execute(( 的返回值,如果出现错误,则返回 false。
我只是运行一个类似于您的示例的代码,并启用了 MySQL 查询日志 我发现所有准备请求都发送到 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();
不,这是预准备语句的主要特征之一。如果要多次运行相同的查询,但使用不同的变量,则准备查询将提高速度。特别是如果您使用事务(需要InnoDB存储引擎(。
-
要回答标题中的问题(这与正文中的问题完全不同(,避免多次准备同一语句的最佳方法显然是避免运行多个类似的查询。
-
从问题正文中回答问题 - 不,DB 引擎/PHP 不够"智能",无法知道它是再次准备的相同查询。每调用一个新的 prepare(( 就会创建另一个语句。我会第一个讨厌这种"聪明"的行为。您的工具越"智能",您获得的结果就越不可预测。
-
为了回答代码中真正的问题,聪明的开发人员会使用正确的工具来省去麻烦。
使用safeMysql,整个混乱将减少到一个查询和一行代码
S0 - 没有多个查询,没有多个$data = $this->dbLink->getAll('SELECT * from somth where id IN (?a)', $arr);
准备,没有多个问题。
顺便说一下,您的代码正在丢失第一个 id。然而,如果您不使用结果,您将失去所有这些,但最后一个。