Они оба делают одно и то же, только по-другому?
Есть ли какая-либо разница, кроме использования
$sth = $db->query("SELECT * FROM table"); $result = $sth->fetchAll();
а также
$sth = $db->prepare("SELECT * FROM table"); $sth->execute(); $result = $sth->fetchAll();
?
query
запускает стандартный SQL- query
и требует, чтобы вы правильно удаляли все данные, чтобы избежать SQL-инъекций и других проблем.
execute
запускает подготовленный оператор, который позволяет связывать параметры, чтобы избежать необходимости избегать или указывать параметры. execute
также будет работать лучше, если вы повторяете запрос несколько раз. Пример подготовленных заявлений:
$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour'); $sth->bindParam(':calories', $calories); $sth->bindParam(':colour', $colour); $sth->execute(); // $calories or $color do not need to be escaped or quoted since the // data is separated from the query
Лучшая практика заключается в том, чтобы придерживаться подготовленных заявлений и execute
для повышения безопасности .
См. Также: Являются ли подготовленные PDO заявления достаточными для предотвращения SQL-инъекций?
Нет, они не то же самое. Помимо экранирования на стороне клиента, которую он предоставляет, подготовленный оператор компилируется на стороне сервера один раз, а затем может быть передан разные параметры при каждом выполнении. Это означает, что вы можете сделать:
$sth = $db->prepare("SELECT * FROM table WHERE foo = ?"); $sth->execute(array(1)); $results = $sth->fetchAll(PDO::FETCH_ASSOC); $sth->execute(array(2)); $results = $sth->fetchAll(PDO::FETCH_ASSOC);
Как правило, они улучшат производительность, хотя и не заметны в небольших масштабах. Подробнее о подготовленных операциях (версия MySQL) .
Ответ Гилайна велик, но я просто хотел добавить, что иногда есть редкие исключения из лучших практик, и вы можете протестировать свою среду, чтобы увидеть, что будет работать лучше всего.
В одном случае я обнаружил, что query
работал быстрее для моих целей, потому что я был массовым переносом доверенных данных из ящика Ubuntu Linux с PHP7 с плохо поддерживаемым драйвером Microsoft ODBC для MS SQL Server .
Я пришел к этому вопросу, потому что у меня был длинный сценарий для ETL, который я пытался сжать за скорость. Мне казалось интуитивным, что query
может быть быстрее, чем prepare
и execute
потому что он вызывает только одну функцию вместо двух. Операция привязки параметров обеспечивает отличную защиту, но она может быть дорогостоящей и, возможно, избегать, если она не нужна.
Учитывая пару редких условий :
Если вы не можете повторно использовать подготовленный оператор, потому что он не поддерживается драйвером Microsoft ODBC .
Если вы не беспокоитесь о дезинфекции входных данных, и простое экранирование является приемлемым. Это может быть так, потому что привязка некоторых типов данных не поддерживается драйвером Microsoft ODBC .
PDO::lastInsertId
не поддерживается драйвером Microsoft ODBC.
Вот метод, который я использовал для проверки своей среды, и, надеюсь, вы можете воспроизвести ее или что-то еще лучше:
Для начала я создал базовую таблицу в Microsoft SQL Server
CREATE TABLE performancetest ( sid INT IDENTITY PRIMARY KEY, id INT, val VARCHAR(100) );
И теперь базовый тест времени для показателей производительности.
$logs = []; $test = function (String $type, Int $count = 3000) use ($pdo, &$logs) { $start = microtime(true); $i = 0; while ($i < $count) { $sql = "INSERT INTO performancetest (id, val) OUTPUT INSERTED.sid VALUES ($i,'value $i')"; if ($type === 'query') { $smt = $pdo->query($sql); } else { $smt = $pdo->prepare($sql); $smt ->execute(); } $sid = $smt->fetch(PDO::FETCH_ASSOC)['sid']; $i++; } $total = (microtime(true) - $start); $logs[$type] []= $total; echo "$total $type\n"; }; $trials = 15; $i = 0; while ($i < $trials) { if (random_int(0,1) === 0) { $test('query'); } else { $test('prepare'); } $i++; } foreach ($logs as $type => $log) { $total = 0; foreach ($log as $record) { $total += $record; } $count = count($log); echo "($count) $type Average: ".$total/$count.PHP_EOL; }
Я играю с несколькими разными пробными версиями и подсчетами в своей конкретной среде и постоянно получаю от 20-30% более быстрых результатов с query
чем prepare
/ execute
5.8128969669342 подготовить
5.8688418865204 подготовить
4.2948560714722 запрос
4.9533629417419 запрос
5.9051351547241 подготовить
4.332102060318 запрос
5.9672858715057 подготовить
5.0667371749878 запрос
3.8260300159454 запрос
4.0791549682617 запрос
4.3775160312653 запрос
3.6910600662231 запрос
5.2708210945129 подготовить
6.2671611309052 подготовить
7.3791449069977 подготовить
(7) подготовка Средняя: 6.0673267160143
(8) запрос Средняя: 4.3276024162769
Мне любопытно посмотреть, как этот тест сравнивается в других средах, таких как MySQL.