Sont-ils tous les deux faire la même chose, mais différemment?
Existe-t-il une différence en dehors de l'utilisation de prepare
entre
$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();
et
$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();
?
query
exécute une instruction SQL standard et vous oblige à échapper correctement toutes les données pour éviter les injections SQL et d'autres problèmes.
execute
exécute une instruction préparée qui vous permet de lier des paramètres afin d'éviter d'avoir à échapper ou à citer ces paramètres. execute
fonctionnera également mieux si vous répétez une requête plusieurs fois. Exemple d'énoncés préparés:
$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
La meilleure pratique consiste à s'en tenir aux instructions préparées et à execute
pour une sécurité accrue .
Voir aussi: Les instructions préparées par le PDO sont-elles suffisantes pour empêcher une injection SQL?
Non, ils ne sont pas pareils. En plus de l'échappement côté client fourni, une instruction préparée est compilée une fois côté serveur, puis différents paramètres peuvent lui être transmis à chaque exécution. Ce qui signifie que vous pouvez faire:
$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);
Ils vous apporteront généralement une amélioration des performances, bien que cela ne soit pas perceptible à petite échelle. En savoir plus sur les instructions préparées (version MySQL) .
La réponse de Gilean C'est bien, mais je voulais juste ajouter qu'il y a parfois de rares exceptions aux meilleures pratiques, et vous voudrez peut-être tester votre environnement dans les deux sens pour voir ce qui fonctionnera le mieux.
Dans un cas, j’ai constaté que query
fonctionnait plus rapidement car j’ transférais en vrac des données fiables à partir d’une machine Ubuntu Linux exécutant PHP7 avec le pilote Microsoft ODBC mal supporté MS SQL Server .
Je suis arrivé à cette question parce que j'avais un long script pour un [~ # ~] etl [~ # ~] que j'essayais de gagner en rapidité. Il me semblait intuitif que query
puisse être plus rapide que prepare
& execute
car il n'appelait qu'une fonction au lieu de deux. L’opération de liaison de paramètres offre une excellente protection, mais elle peut être coûteuse et éventuellement évitée si elle n’est pas nécessaire.
Étant donné quelques conditions rares :
Si vous ne pouvez pas réutiliser une instruction préparée car elle n'est pas prise en charge par le pilote Microsoft ODBC .
Si vous n'êtes pas inquiet à propos de la désinfection, une entrée et une sortie simples sont acceptables. Cela peut être le cas car la liaison de certains types de données n'est pas prise en charge par le pilote Microsoft ODBC .
PDO::lastInsertId
n'est pas pris en charge par le pilote Microsoft ODBC.
Voici une méthode que j'ai utilisée pour tester mon environnement et j'espère que vous pourrez le répliquer ou quelque chose de mieux dans le vôtre:
Pour commencer, j'ai créé une table de base dans Microsoft SQL Server
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
Et maintenant, un test chronométré de base pour les mesures de performance.
$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;
}
J'ai joué avec plusieurs essais différents et des comptes dans mon environnement spécifique et obtiens systématiquement des résultats 20 à 30% plus rapides avec query
qu'à prepare
/execute
5.8128969669342 préparer
5.8688418865204 préparer
4.2948560714722 requête
4.9533629417419 requête
5.9051351547241 préparer
4.332102060318 requête
5.9672858715057 prepare
5.0667371749878 requête
3.8260300159454 requête
4.0791549682617 requête
4.3775160312653 requête
3.6910600662231 requête
5.2708210945129 prepare
6.2671611309052 préparer
7.3791449069977 préparer
(7) préparer Moyenne: 6.0673267160143
(8) requête Moyenne: 4.3276024162769
Je suis curieux de voir comment ce test se compare dans d'autres environnements, comme MySQL.