Відповіді:
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.