Как работают подготовленные заявления?

StackOverflow https://stackoverflow.com/questions/54980

  •  09-06-2019
  •  | 
  •  

Вопрос

Я пишу несколько процедур БД и использую подготовленные операторы.Моя среда — PDO с PHP5.

Я понимаю, что подготовленные операторы в первую очередь обеспечивают выигрыш в производительности, а также некоторые вспомогательные бонусы, такие как отсутствие необходимости вручную экранировать входные данные SQL.

Мой вопрос касается производительности.

Ниже приведены две реализации функции getPrice, которая принимает идентификатор продукта и возвращает его цену.

getPrice_A повторно использует один и тот же объект PDOStatement при последующих вызовах в рамках одного и того же выполнения сценария.Это необходимо или рекомендуется?Если да, то есть ли способ избежать дублирования этого дополнительного кода для каждого метода get*() в каждой отдельной модели?

getPrice_B создает новый объект PDOStatement при каждом вызове.Сможет ли СУБД признать, что этот оператор уже подготовлен, и при этом сможет пропустить некоторую работу?Другими словами, правильно ли эта реализация использует преимущества производительности подготовленных операторов?

Написав все это и прочитав, я полагаю, что getPrice_B подойдет, а getPrice_A дает незначительную выгоду, которая может стоить или не стоит дополнительных усложнений.

Хотя хотелось бы услышать наверняка кого-нибудь более знающего.

Предположим, что $pdo является допустимым подключенным объектом PDO в примерах ниже.

<?php
class Product {
    static function &getPrice_A($id) {
        static $stmt;
        if (!$stmt) {
            $stmt = $pdo->prepare('SELECT price FROM products WHERE id = ?');
        }
        $stmt->execute(array($id));
        return $stmt->fetchColumn(0);
    }

    static function &getPrice_B($id) {
        $stmt = $pdo->prepare('SELECT price FROM products WHERE id = ?');
        $stmt->execute(array($id));
        return $stmt->fetchColumn(0);
    }
}

// example usage:
$price = Product::getPrice(4982);
echo "Product 4982 costs $price\n";
Это было полезно?

Решение

Насколько я понимаю, подготовленные операторы будут повторно использовать сгенерированный план SQL, если это один и тот же оператор, поэтому база данных будет видеть тот же подготовленный оператор, и ей не придется выполнять работу, чтобы выяснить, как выполнить запрос к базе данных.Я бы сказал, что дополнительная работа по сохранению подготовленного оператора в Product::getPrice_A обычно это не очень полезно, скорее потому, что это может скрыть код, а не проблема с производительностью.Когда речь идет о производительности, я считаю, что всегда лучше сосредоточиться на ясности кода, а затем на производительности, когда у вас есть реальная статистика, указывающая на проблему.

Я бы сказал: «Да, дополнительная работа не нужна» (независимо от того, действительно ли она повышает производительность).Кроме того, я не очень большой эксперт по БД, но о приросте производительности подготовленных операторов я слышал от других, и он происходит на уровне базы данных, а не на уровне кода (поэтому, если код на самом деле вызывает параметризованный оператор в фактическая БД, тогда БД может кэшировать эти планы выполнения...хотя в зависимости от базы данных вы можете получить выгоду даже без параметризованного оператора).

В любом случае, если вы действительно обеспокоены (и видите) проблемы с производительностью базы данных, вам следует рассмотреть решение для кэширования...из которых я очень рекомендую кэширование памяти.С помощью такого решения вы можете кэшировать результаты запросов и даже не обращаться к базе данных для вещей, к которым вы часто обращаетесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top