Gilean's answer es genial, pero solo quería agregar que a veces existen raras excepciones a las mejores prácticas, y es posible que desee probar su entorno en ambos sentidos para ver qué funciona mejor.
En un caso, encontré que query
funcionó más rápido para mis propósitos porque estaba transfiriendo a gran escala los datos de confianza de una caja de Ubuntu Linux que ejecuta PHP7 con el Microsoft ODBC driver for MS SQL Server con soporte deficiente.
Llegué a esta pregunta porque tenía un script de ejecución larga 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 llamaba solo una función en lugar de dos. La operación de enlace de parámetros proporciona una excelente protección, pero puede ser costoso y posiblemente evitado si no es necesario.
Dadas las condiciones de un par raras:
Si no se puede reutilizar una declaración preparada porque it's not supported by the Microsoft ODBC driver.
Si no está preocupado por la desinfección de la entrada y el simple escape es aceptable. Este puede ser el caso porque binding certain datatypes isn't supported by the Microsoft ODBC driver.
PDO::lastInsertId
no es compatible con el controlador ODBC de Microsoft.
Aquí hay un método que utiliza para probar mi entorno, y es de esperar que se puede replicar o algo mejor en la suya:
Para empezar, 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 es una prueba básica de tiempo 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
que prepare
/execute
5,8128969669342 preparar
5.8688418865204 preparan
4.2948560714722 consulta
4.9533629417419 consulta
5.9051351547241 prepare
4,2060318 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) se preparan media: 6.0673267160143
(8) consulta A verage: 4.3276024162769
Tengo curiosidad por ver cómo esta prueba se compara en otros entornos, como MySQL.
El enlace lleva a la pregunta con una respuesta bastante estúpida, ya criticada en los comentarios. –
Así que si usas una preparación en ': calories' es ese tipo de equivalente de' mysql_real_escape_string() 'para detener las inyecciones o necesitas más que' $ sth-> bindParam (': calories', $ calories) ; 'para aumentar la seguridad? – Dan
¿Por qué 'query' devuelve un * PDOStatement *, en lugar de un * bool * como' execute'? – Leo