Использование нескольких подготовленных заявлений PDO одновременно - PullRequest
2 голосов
/ 08 февраля 2020

Это запрос на подтверждение / уточнение на основе очень легко пропущенного комментария за 6 лет go в PHP. net руководстве для PDO :: prepare, которое у меня есть. не видел обсуждаемых в другом месте (даже в отличном блоге phpdelusion). Это такая мощная возможность, если это правда, что я чувствую, что заслуживает немного более широкого охвата и выделения поиска для других (или нуждается в опровержении, если нет).

Вот комментарий (Хейли Уотсон):

Можно заранее подготовить несколько заявлений против одного соединения. Пока это соединение остается открытым, операторы могут выполняться и извлекаться из любого числа в любом порядке; их шаги "prepare-execute-fetch" могут чередоваться любым подходящим способом.

Так что, если вы, вероятно, будете часто использовать несколько операторов (возможно, в пределах oop транзакций), вам может понравиться рассмотреть вопрос о подготовке всех утверждений, которые вы будете использовать заранее.

У меня есть код, который должен работать как (псевдокод):

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

Согласно этому комментарию, я может создать ДВЕ подготовленные операторы ДО l oop, один для запроса на обновление и один для запроса на удаление, а затем выполнить (только) в пределах l oop. Пока дескрипторы различны и сохраняются, соединение должно кэшировать оба, я могу использовать их взаимозаменяемо, и мне не нужно было бы делать какие-либо операторы SQL, анализирующие INSIDE l oop, что было бы очень неэффективно:

// 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);
}

Поскольку большинство вопросов здесь обсуждают только использование одного подготовленного оператора за раз, и это имеет прекрасные последствия для эффективности кода, если его широко применять, кто-то хотел бы подтвердить, что это действительно так (по крайней мере, из * 1028) *)? Если это так, я думаю, что другие полезные приложения для этой формы кода могут быть использованы в решениях.

Ответы [ 2 ]

4 голосов
/ 09 февраля 2020

Нет проблем с использованием нескольких подготовленных операторов одновременно и выполнением их не по порядку.

Вы можете запустить код, подобный следующему, с помощью переплетенных операторов, и он будет работать.

$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 проблема. Вы подготавливаете внутренний запрос один раз, а затем выполняете его внутри l oop несколько раз.

Однако это может быть проблемой с производящими запрос запросами, если вы хотите выполнить небуферизованный запрос (он очень редко используется). 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());

Он выдаст:

Неустранимая ошибка: Uncaught PDOException: SQLSTATE [ HY000]: общая ошибка: 2014. Невозможно выполнить запросы, когда другие небуферизованные запросы активны. Рассмотрите возможность использования PDOStatement :: fetchAll (). В качестве альтернативы, если ваш код будет работать только с mysql, вы можете включить буферизацию запросов, установив атрибут PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY.

1 голос
/ 08 февраля 2020

Хороший вопрос! Первый оператор?

    $id = '2';
    $username = 'John';
    if ($id === 2){
        $array = array(':username'=> $username, ':id'=>$id);
        $sql = "UPDATE users SET username = ? WHERE id = ?";
    }else{
        $array = array(':id'=>$id);
        $sql = "DELETE FROM users WHERE id = ?";
    }

$stmt = $pdo->prepare($sql);
$stmt->execute($array);

Второй оператор:

$sql = "UPDATE users SET username = ? WHERE id = ?";
$sql = "DELETE FROM users WHERE id = ?";
$stmt1 = $pdo->prepare($sql);
$stmt2 = $pdo->prepare($sql);

    if ($id === 2){
        $array = array(':username'=> $username, ':id'=>$id);
        $stmt1->execute($array);
    }else{
        $array = array(':id'=>$id);
        $stmt2->execute($array);
    }

Простые операторы:

$stmt = $pdo->prepare("UPDATE users SET username = ? WHERE id = ?")->execute([':username'=> $username, ':id'=>$id]);
$stmt = null;

$stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([':id'=>$id]);
$stmt = null;

Первый оператор выполняется на 1 секунду быстрее второго оператора.

Запуск отдельных операторов внизу, обновление и удаление одновременно гораздо быстрее, чем другие.

Это из-за операторов if?

Я выполняю php 7.4.0 и mysql 8.0

Обновлено, если кто-то хочет попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...