Запрос PDO против выполнения
Они оба делают то же самое, только по-другому?
есть ли разница помимо использования prepare
между
$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();
и
$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();
?
3 ответа:
query
запускает стандартную инструкцию SQL и требует, чтобы вы правильно экранировали все данные, чтобы избежать инъекций 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
для повышения безопасности.Читайте также: являются ПДО подготовленных заявлений достаточно, чтобы предотвратить 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).
Gilean это это здорово, но я просто хотел добавить, что иногда бывают редкие исключения из лучших практик, и вы можете проверить свою среду в обоих направлениях, чтобы увидеть, что будет работать лучше всего.
в одном случае, я обнаружил, что
query
работал быстрее для моих целей, потому что я массово передавал доверенные данные из Ubuntu Linux box под управлением PHP7 с плохо поддерживаемым драйвер Microsoft ODBC для MS SQL Server.I пришел к этому вопросу, потому что у меня был длинный скрипт для 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.