Должен ли я использовать подготовленные операторы для MySQL в PHP PERFORMANCE-WISE? - PullRequest
21 голосов
/ 06 февраля 2010

Я понимаю преимущества безопасности подготовленных операторов в MySQL. Нет необходимости освещать эту тему здесь. Я задаюсь вопросом об их аспекте производительности.

Теперь я знаю, что когда запрос с использованием подготовленного оператора выполняется дважды в одном скрипте PHP, это быстрее, потому что запрос анализируется только один раз, один раз для каждого запроса. Для подготовки клиент совершает одну поездку, затем дважды отправляет данные с использованием двоичного протокола. Бинарный протокол работает быстрее, и вам не придется анализировать второй раз.

Однако как насчет случая, когда я хочу выполнить запрос только один раз в одном скрипте PHP? Может показаться, что использование подготовленного оператора хуже, потому что вы совершаете две поездки на сервер: одну для подготовки и одну для отправки данных. Выгода от анализа только один раз потеряна, и вы оштрафованы за эту вторую поездку. Если в двоичном формате данные недостаточно малы, вы теряете их, используя подготовленный оператор, верно?

Тем не менее, я прочитал несколько противоречивых отчетов о том, что делают PHP библиотеки mysqli или PDO? Кто-нибудь из них кэширует подготовленный оператор при выполнении скрипта? Придется ли серверу снова анализировать подготовленный оператор при последующей загрузке страницы или нет? Если ответ «нет», то оператор не должен анализироваться во второй загрузке страницы, тогда может показаться, что подготовленные операторы лучше, даже если вы выполняете запрос только один раз для загрузки страницы.

Пожалуйста, примите во внимание, если что-то изменилось между версиями MySQL по этому поводу. Вы можете смело предположить, что я использую PHP 5.2

РЕДАКТИРОВАТЬ: просто чтобы прояснить, я хочу ответ для MySQL и PHP конкретно, указав версию MySQL и, если это когда-либо отличалось, и ТОЛЬКО учитывать производительность, а не простоту использования или безопасность.

ОБНОВЛЕНИЕ: Я принял ответ, который получил, потому что в последующем комментарии было несколько хороших идей. Я все еще немного разочарован тем, что, похоже, никто не может ответить суть вопроса, который я задал, с какой-либо определенностью. Наверное, иногда ответ на самом деле таков: «это зависит».

Ответы [ 5 ]

12 голосов
/ 08 февраля 2010

История

Это был мой первый ответ на Stackoverflow. С тех пор многое изменилось, особенно в отношении устаревания и удаления API mysql. Даже если вы все еще на php 5.6, mysql_ * api не должен использоваться. Теперь PDO или MySQL являются единственными вариантами выбора. PDO лучше по многим причинам.

Кешируются ли подготовленные операторы при загрузке страницы?

Я прочитал несколько противоречивых отчетов о том, что такое PHP MySQLi или PDO библиотеки делают? Сделайте любой из них кэшировать подготовленный оператор через выполнение скрипта?

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

Для больших вставок (тысячи строк) Возможно, больший прирост можно получить, поместив ваши данные в текстовый файл и загрузив его с помощью LOAD DATA IN FILE. Это намного быстрее, чем серия вставок.

Оригинальный ответ

Правда в том, что иногда mysqli быстрее, а иногда mysql api быстрее. Но разница действительно очень мала. Если вы посмотрите на какие-либо тесты производительности в Интернете, разница в действительности составляет всего 10–20 миллисекунд. Лучший способ повысить производительность - оптимизировать дизайн стола.

Многие из тестов, которые «доказывают», что старый API быстрее, удобно забывают, что для максимальной безопасности mysql_real_escape_string () следует вызывать для каждой переменной, используемой в запросе.

Запросы кешируются сервером, если и только если данные по всем таблицам, которые используются в запросе, остались без изменений.

Жду еще одного обновления с актуальными номерами

7 голосов
/ 13 октября 2010

«Использование готовых утверждений никогда не бывает плохой идеей»

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

Подготовленные операторы специально разработаны для узких внутренних циклов в вашей бизнес-логике, когда вы будете снова и снова вызывать один и тот же базовый запрос, хорошим примером является параметризованный запрос, такой как:

SELECT name, address, phone from tbl WHERE id = ?

и у вас разные идентификаторы при каждом вызове. Таким образом, стоит подготовить дополнительную поездку в БД для подготовки, потому что вы, вероятно, будете вызывать ее сотни или тысячи раз и просто изменить параметр. Но вы должны удалить подготовленный оператор из кэша или закрыть соединение в конце, скажем, вашего сценария без сохранения состояния (php, perl, jsp, ruby ​​и т. Д.).
Если вы не удалите подготовленный оператор и используете пул соединений, вы обязаны со временем заполнить кэш и получить неприятную ошибку «Невозможно создать более операторов max_prepared_stmt_count». Я говорю из опыта, поэтому подумайте, действительно ли вам нужны подготовленные операторы, потому что вы точно знаете, что будете повторять один и тот же параметризованный запрос снова и снова в тесном цикле.
Если нет, то, что вы, вероятно, ищете, это позволить mysql использовать свой основной кеш запросов, который отличается от подготовленного списка операторов и который, на мой взгляд, ведет себя как настоящий LRU-кеш.

1 голос
/ 26 сентября 2014

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

Например, когда мне нужно вставить сотни строк в одну загрузку страницы, я нахожу:

$pdo -> query("INSERT INTO table (field1, field2, ...) VALUES (".$pdo -> quote($value1).", ".$pdo -> quote($value2).", ...), (row2), (row3), ..., (row100), ...");

НАМНОГО быстрее чем:

$stmt = $pdo -> prepare("INSERT INTO table (field1, field2, ...) VALUES (:value1, :value2, ...)");
foreach (/* some hundred times */) {
  $stmt -> execute(array('value1' => $value1, 'value2' => $value2, ...));
}

UPDATE

Я написал этот ответ 4 года назад, с тех пор я узнал что-то новое об этом.

Чтобы подготовленный оператор, который многократно выполнялся сотни раз, был быстрым, вы должны заключить все выполнения в одну транзакцию .

Однако я никогда не проверял, что является более быстрой, неподготовленной INSERT для одной партии с 1000 строками или 1000 выполнений подготовленной INSERT, заключенной в транзакцию.

0 голосов
/ 06 февраля 2010

Что именно вы имеете в виду под "анализом на второй странице"?

Каждый PHP-процесс / поток / посетитель, который выполняет тот же сценарий снова, НЕ будет препятствовать MySQL повторно анализировать запрос, чтобы подготовить оператор, так как он действителен для каждого соединения, поэтому он очень эффективен для запросов, повторяемых в одном и том же сценарий.

Теперь я не могу спорить о подготовке + выполнение или простом запросе с точки зрения производительности (без повторных запросов);

Но, чтобы уберечь mysql от разбора сложного запроса при каждом выполнении скрипта, вы должны использовать хранимые процедуры; запрос будет просто CALL items(date,search_etc,id); вместо SELECT i.id FROM products as p JOIN item_prodct as t ON... JOIN items as i... ON... WHERE ... p.date ... i.search_etc ...

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

0 голосов
/ 06 февраля 2010

Использование готовых утверждений никогда не бывает плохой идеей. Я не использовал их недавно с MySQL, но я интенсивно использовал их с SQLSERVER - и они прекрасно работают.

Библиотека PDO, вероятно, не выполняет никакого кэширования, но база данных подготовит оператор.

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

...