Respuestas:
query
ejecuta una instrucción SQL estándar y requiere que escapes adecuadamente de todos los datos para evitar inyecciones SQL y otros problemas.
execute
ejecuta una declaración preparada que le permite vincular parámetros para evitar la necesidad de escapar o citar los parámetros. execute
también funcionará mejor si repite una consulta varias veces. Ejemplo de declaraciones preparadas:
$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 mejor práctica es seguir las declaraciones preparadas y execute
aumentar la seguridad .
Ver también: ¿Son suficientes las declaraciones preparadas para PDO para evitar la inyección de SQL?
: calories
es ese el equivalente de mysql_real_escape_string()
detener las inyecciones o necesita algo más que $sth->bindParam(':calories', $calories);
aumentar la seguridad?
query
devuelve un PDOStatement , en lugar de un bool como execute
?
No, no son lo mismo. Además del escape en el lado del cliente que proporciona, una declaración preparada se compila en el lado del servidor una vez, y luego se pueden pasar diferentes parámetros en cada ejecución. Lo que significa que puedes hacer:
$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);
En general, le brindarán una mejora en el rendimiento, aunque no se notará a pequeña escala. Lea más sobre declaraciones preparadas (versión MySQL) .
La respuesta de Gilean es excelente, pero solo quería agregar que a veces hay raras excepciones a las mejores prácticas, y es posible que desee probar su entorno en ambos sentidos para ver qué funcionará mejor.
En un caso, descubrí que query
funcionaba más rápido para mis propósitos porque estaba transfiriendo en masa datos confiables desde una caja de Ubuntu Linux que ejecuta PHP7 con el controlador ODBC de Microsoft mal soportado para MS SQL Server .
Llegué a esta pregunta porque tenía un script de larga ejecución para un ETL que estaba tratando de exprimir para obtener velocidad. Me pareció intuitivo que query
podría ser más rápido que prepare
& execute
porque estaba llamando solo a una función en lugar de dos. La operación de enlace de parámetros proporciona una protección excelente, pero puede ser costosa y posiblemente evitarse si no es necesario.
Dadas un par de condiciones raras :
Si no puede reutilizar una declaración preparada porque no es compatible con el controlador ODBC de Microsoft .
Si no está preocupado por desinfectar la entrada y el escape simple es aceptable. Este puede ser el caso porque la vinculación de ciertos tipos de datos no es compatible con el controlador ODBC de Microsoft .
PDO::lastInsertId
no es compatible con el controlador ODBC de Microsoft.
Aquí hay un método que usé para probar mi entorno, y espero que puedas replicarlo o algo mejor en el tuyo:
Para comenzar, he creado una tabla básica en Microsoft SQL Server
CREATE TABLE performancetest (
sid INT IDENTITY PRIMARY KEY,
id INT,
val VARCHAR(100)
);
Y ahora una prueba cronometrada básica para las métricas de rendimiento.
$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;
}
He jugado con diferentes ensayo múltiple y recuentos en mi entorno específico, y recibe constantemente entre un 20-30% más rápido con resultados query
de prepare
/execute
5,8128969669342 preparar
5,8688418865204 preparar
4,2948560714722 consulta
4,9533629417419 consulta
5,9051351547241 preparar
4,332102060318 consulta
5,9672858715057 preparar
5,0667371749878 consulta
3,8260300159454 consulta
4,0791549682617 consulta
4,3775160312653 consulta
3,6910600662231 consulta
5,2708210945129 preparar
6,2671611309052 preparar
7,3791449069977 preparar
(7) preparar media: 6.0673267160143
(8) consulta media: 4,3276024162769
Tengo curiosidad por ver cómo esta prueba se compara en otros entornos, como MySQL.