Я пишу несколько подпрограмм DB, и я использую подготовленные инструкции. Моя среда PDO с PHP5.
Я понимаю, что подготовленные заявления в основном обеспечивают преимущество в производительности, а также некоторые вспомогательные бонусы, такие как отсутствие ручных входных данных SQL-escape.
Мой вопрос касается части производительности.
У меня есть две реализации функции 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
обычно не очень полезна, потому что это может затмить код, а не проблему производительности. Когда речь идет о производительности, я считаю, что всегда лучше сосредоточиться на ясности кода, а затем на производительности, когда у вас есть реальная статистика, указывающая на проблему.
Я бы сказал: «Да, лишняя работа не нужна» (независимо от того, действительно ли это повышает производительность). Кроме того, я не очень большой эксперт по БД, но прирост производительности подготовленных операторов – это то, что я слышал от других, и оно находится на уровне базы данных, а не на уровне кода (поэтому, если код действительно вызывает параметризованный оператор на фактическая БД, тогда БД может выполнить кэширование плана выполнения … хотя в зависимости от базы данных вы можете получить выгоду даже без параметризованного оператора).
В любом случае, если вы действительно волнуетесь (и видите) проблемы с производительностью базы данных, вы должны изучить решение для кеширования … из которого я бы настоятельно рекомендовал memcached . Благодаря такому решению вы можете кэшировать результаты своих запросов и даже не попадать в базу данных для получения доступа к часто используемым ресурсам.