php - 一次使用多个 PDO 准备好的语句

标签 php mysql pdo

这是一个基于 6 年前 PHP.net PDO::prepare 手册中非常很容易错过的评论的确认/澄清请求,我没有在其他地方看到过该评论(即使在伟大的 phpdelusions 博客中)。如果这是真的,那么它的可能性就非常大,我觉得它值得更广泛的覆盖范围和搜索突出显示(如果不是,则需要揭穿)。

这是评论(海莉·沃森):

It is possible to prepare in advance several statements against a single connection. As long as that connection remains open the statements can be executed and fetched from as often as you like in any order; their "prepare-execute-fetch" steps can be interleaved in whichever way is best.

So if you're likely to be using several statements often (perhaps within a loop of transactions), you may like to consider preparing all the statements you'll be using up front.

我有一些代码必须像(伪代码)一样运行:

foreach (fetchAll row with PDO) {
    process row results
    if (condition)
        update table with processed results
    else
        delete row no longer needed
}

根据该评论,我可以在循环之前创建两个准备好的语句,一个用于更新查询,一个用于删除查询,然后(仅)在循环内执行。只要句柄不同并保留,连接就应该缓存两者,我可以互换使用它们,并且不必在循环内进行任何 SQL 语句解析,这将非常低效:

// do statement prepare/execute/fetchAll for main loop, then...
$update_stmt = $PDO->prepare($update_query);
$delete_stmt = $PDO->prepare($delete_query);
foreach (fetchAll row) {
    process row results
    if (condition)
        $update_stmt->execute(some_processed_values);
    else
        $delete_stmt->execute(some_other_values);
}

由于这里的大多数问题只讨论一次使用一个准备好的语句,如果广泛应用,这对代码效率有很好的影响,有人想确认这确实是这样吗(至少从 PHP7 开始)?如果是这样,我想这种形式的代码的其他简洁应用程序可以在解决方案中共享。

最佳答案

同时使用多个准备好的语句并且乱序执行它们是没有问题的。

您可以使用交织的语句运行如下代码,它会起作用。

$stmt1 = $pdo->prepare('INSERT INTO addplate(Plate) VALUES(?)');
$stmt2 = $pdo->prepare('UPDATE addplate SET Plate=? WHERE Plate=?');

$stmt1->execute(['val1']);
$stmt2->execute(['val2', 'val1']);
$stmt1->execute(['val1']);
$stmt2->execute(['val2', 'val1']);
$stmt1->execute(['val1']);

当由于某种原因您无法避免 N+1 问题时,这可以为您带来一些性能优势。您准备一次内部查询,然后在循环内多次执行它。

但是,如果您想运行 unbuffered query,这可能会成为生成结果的查询的问题。 (很少使用)。 PDO 默认情况下执行缓冲查询,因此您需要将它们关闭才能遇到此问题。

$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

$stmt1 = $pdo->prepare('SELECT * FROM addplate WHERE Plate=?');
$stmt2 = $pdo->prepare('SELECT * FROM addplate WHERE Plate=?');

$stmt1->execute(['val1']);
var_dump($stmt1->fetch());
$stmt2->execute(['val2']); // <-- Error if stmt1 still has more records
var_dump($stmt2->fetch());

它将产生:

Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.

关于php - 一次使用多个 PDO 准备好的语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60130072/

相关文章:

MySQL从表中每个不同外键的10行中选择id

php - 导致 sum() 到多个结果的分组表

php - 使用 MySQL 和 PHP PDO 发出基于 SELECT 语句的运行查询

php - 消除使用 PHP 进行 Mod 重写的需要

php - 在 PHP 中声明变量有问题吗?

php - 使用 PHPExcel 从 excel 中读取数字时出现问题

PHP 没有那么致命的错误 "new SoapClient()"

php - laravel 具有内部关系的多对多关系

javascript - 如何使用输入数据库的日期禁用日期选择器中的日期?

php - 如何与PHP一起显示带有限制的mysql数组