Ответы:
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
для повышения безопасности .
См. Также: Достаточно ли подготовленных операторов PDO для предотвращения внедрения SQL?
: calories
препарат, это эквивалент mysql_real_escape_string()
остановки инъекций, или вам нужно больше, чем просто $sth->bindParam(':calories', $calories);
для повышения безопасности?
query
возвращает PDOStatement , вместо BOOL , как execute
?
Нет, они не такие. Помимо экранирования на стороне клиента, который он предоставляет, подготовленный оператор компилируется на стороне сервера один раз, а затем может передавать различные параметры при каждом выполнении. Это означает, что вы можете:
$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.