Declaración preparada
En sistemas de gestión de base de datos, un declaración preparada o instrucción parametrizada es una característica utilizada para ejecutar repetidamente las declaraciones de igual o similar de bases de datos con alta eficiencia. Se usa generalmente con SQL declaraciones como la de consultas o actualizaciones, la declaración preparada toma la forma de un plantilla en el cual ciertos valores constantes son sustituidos durante cada ejecución.
El flujo de trabajo típico del uso de una declaración preparada es como sigue:
- Preparar:: La plantilla de declaración es creada por la aplicación y envía al sistema de gestión de bases de datos (DBMS). Ciertos valores se quedan sin especificar, llamado parámetros, marcadores de posición o enlazar las variables (marcado con "?" más abajo):
Inserte en producto (nombre, precio) valores (?,?)
- El DBMS analiza, compila y ejecuta optimización de consultas en la plantilla de declaración y almacena el resultado sin ejecutarlo.
- Ejecutar:: En un momento posterior, fuentes de la aplicación (o une) los valores de los parámetros y el DBMS ejecuta la instrucción (posiblemente devolviendo un resultado). La aplicación puede ejecutar la sentencia tantas veces como quiera con diferentes valores. En este ejemplo, se puede suministrar 'Pan' para el primer parámetro y '1.00' para el segundo parámetro.
En comparación con ejecutar SQL declaraciones directamente, sentencias preparadas ofrecen dos ventajas principales:[1]
- La sobrecarga de compilar y optimización de la declaración se incurre en una sola vez, aunque varias veces se ejecuta la instrucción. Optimización no puede realizarse en el momento que se compila la declaración preparada, por dos razones: el mejor plan puede depender de los valores específicos de los parámetros y el mejor plan puede cambiar como tablas y los índices cambian con el tiempo.[2]
- Declaraciones preparadas son resistentes contra Inyección SQL, porque los valores de parámetro, que son transmitidos posteriormente usando un protocolo diferente, no necesitan ser escapados correctamente. Si la plantilla original de la declaración no se deriva de entrada externa, inyección de SQL no puede ocurrir.
Por otro lado, si se ejecuta una consulta sólo una vez, sentencias preparadas del servidor puede ser más lento debido a la ida y vuelta adicional al servidor.[3] Limitaciones de aplicación también pueden llevar a sanciones de rendimiento: algunas versiones de MySQL no caché de resultados de las consultas preparadas,[4] y algunas bases de datos como PostgreSQL no realizar la optimización de consultas adicionales durante la ejecución.[5][6]
A procedimiento almacenado, que también es precompilado y almacenado en el servidor para su posterior ejecución, tiene ventajas similares. A diferencia de un procedimiento almacenado, una declaración preparada normalmente no está escrita en un lenguaje procesal y no puede utilizar o modificar variables o utilizar estructuras de flujo de control, confiando en su lugar en el lenguaje de consulta de base de datos declarativo. Debido a su simplicidad y emulación del lado del cliente, declaraciones preparadas son más portátiles a través de los vendedores.
Contenido
- 1 Soporte de software
- 2 Ejemplos
- 2.1 Java JDBC
- 2.2 PHP PDO
- 2.3 PERL DBI
- 2.4 C# ADO.NET
- 2.5 DB-API de Python
- 3 Referencias
Soporte de software
Declaraciones preparadas son ampliamente apoyadas por importantes bases de datos, incluyendo MySQL,[7] Oracle,[8] DB2,[9] Microsoft SQL Server,[10] y PostgreSQL.[5] Declaraciones preparadas normalmente son ejecutadas a través de un protocolo binario no SQL, eficiencia y protección de la inyección de SQL, pero con algunas bases de datos como MySQL también están disponibles mediante una sintaxis SQL para propósitos de depuración.[11]
Un número de lenguajes de programación apoyar declaraciones preparadas en sus bibliotecas estándar y los emulará el lado del cliente incluso si el DBMS subyacente no es compatible con ellos, incluyendo Javaes JDBC,[12] Perles DBI,[13] PHPes DOP [1] y Pythondel DB-API.[14] Emulación del lado del cliente puede ser más rápido para las consultas que se ejecutan una sola vez, reduciendo el número de viajes de ida al servidor, pero es generalmente más lenta para las consultas ejecutadas muchas veces. Igualmente efectivamente resiste ataques de inyección SQL.
Muchos tipos de ataques de inyección SQL pueden eliminarse por desactivación de los literales, efectivamente que requieren el uso de comandos preparados; a partir de 2007 sólo H2 admite esta función.[15]
Ejemplos
Java JDBC
Este ejemplo utiliza Java y el JDBC API:
Java.SQL.PreparedStatement stmt = conexión.prepareStatement( ¿"Seleccionar * de usuarios donde USERNAME =? Y CUARTO =? "); stmt.setString(1, nombre de usuario); stmt.setInt(2, roomNumber); stmt.executeQuery();
Java PreparedStatement
proporciona "setters" ()setInt(int), setString(String), setDouble(double),
etc.). para todos los tipos principales de datos integrado.
PHP PDO
Este ejemplo utiliza PHP y Objetos de datos PHP (DOP):
$stmt = $dbh->preparar(¿"Seleccionar * de usuarios donde USERNAME =? Y LA CONTRASEÑA =? "); $stmt->ejecutar(matriz($username, $pass));
PERL DBI
Este ejemplo utiliza Perl y DBI:
my $stmt = $dbh->preparar(¿' Seleccionar * de usuarios donde USERNAME =? Y LA CONTRASEÑA =?'); $stmt->ejecutar($username, $password);
C# ADO.NET
Este ejemplo utiliza C# y ADO.NET:
usando (Comando SqlCommand = conexión.CreateCommand()) { comando.CommandText = "Seleccionar * de usuarios donde USERNAME = @username y sala = @room"; comando.Parámetros.AddWithValue("@username", nombre de usuario); comando.Parámetros.AddWithValue("@room", sala); usando (SqlDataReader dataReader = comando.ExecuteReader()) { // ... } }
ADO.NET SqlCommand
aceptará cualquier tipo para el valor
parámetro de AddWithValue
, y conversión de tipos se produce automáticamente. Note el uso de "parámetros con nombre" (es decir "@username"
) en lugar de "?"
-Esto le permite utilizar un parámetro varias veces y en cualquier orden arbitrario en el texto del comando query.
Sin embargo, no debe utilizarse el método AddWithValue con tipos de datos de longitud variable, como varchar o nvarchar. Esto es porque .NET asume la longitud del parámetro a ser la longitud de un valor dado, en lugar de conseguir la longitud real de la base de datos mediante reflexión. La consecuencia de esto es que un plan de consulta diferentes es compilado y almacenado para cada diversa longitud. En general, el número máximo de planes 'duplicados' es el producto de las longitudes de las columnas de longitud variable según se especifica en la base de datos. Por esta razón, es importante que utilice el método Add estándar para las columnas de longitud variable:
comando.Parámetros.Añadir(ParamName, VarChar, ParamLength).Valor = ValorParam, donde ParamLength es la longitud según se especifica en la base de datos.
Puesto que el método Add estándar debe ser utilizado para tipos de datos de longitud variable, es una buena costumbre de utilizarlo para todos los tipos de parámetro.
DB-API de Python
Este ejemplo utiliza Python DB-API con SQLite y paramstyle = 'qmark'
:
importación sqlite3 conn = sqlite3.conectar(': memory:') c = conec.cursor() _users = [('madre', 'rojo'), ('padre', 'verde'), ('me', 'azul')] c.executemany("INSERT INTO usuarios valores (?,?)", _users) params = ('hermana', 'amarillo') c.ejecutar(¿' Seleccionar * de usuarios WHERE username =? Y cuarto =?', params) c.fetchone()
Referencias
- ^ a b El grupo de documentación de PHP. "Sentencias preparadas y procedimientos almacenados". Manual de PHP. 25 de septiembre de 2011.
- ^ Petrunia, Sergey (28 de abril de 2007). "Optimizador MySQL y declaraciones preparadas". Blog de Sergey Petrunia. 25 de septiembre de 2011.
- ^ Zaitsev, Peter (02 de agosto de 2006). "Sentencias preparadas de MySQL". Blog de rendimiento de MySQL. 25 de septiembre de 2011.
- ^ "Punto 7.6.3.1. cómo opera la caché de consultas". Manual de referencia de MySQL 5.1. Oracle. 26 de septiembre de 2011.
- ^ a b "PREPARAR". Documentación de PostgreSQL 9.0.5. PostgreSQL Global Development Group. 26 de septiembre de 2011.
- ^ Smith, Lukas Kahwe (14 de mayo de 2008). "Preparado declaración gotchas". Poo-tee-weet. 26 de septiembre de 2011.
- ^ Oracle. "20.9.4. C API sentencias preparadas". Manual de referencia de MySQL 5.5. 27 de marzo de 2012.
- ^ "13 oracle SQL dinámico". Pro * Guía del programador de C y C++ precompilador, liberar 9.2. Oracle. 25 de septiembre de 2011.
- ^ "Utilizando las declaraciones de preparar y ejecutar". Centro de información, versión 5 Release 4 i5/OS. IBM. 25 de septiembre de 2011.
- ^ "SQL Server 2008 R2: preparación de sentencias SQL". MSDN Library. Microsoft. 25 de septiembre de 2011.
- ^ Oracle. "Sintaxis 12.6. SQL para comandos preparados". Manual de referencia de MySQL 5.5. 27 de marzo de 2012.
- ^ "Mediante declaraciones preparadas". Los tutoriales de Java. Oracle. 25 de septiembre de 2011.
- ^ Bunce, Tim. "Especificación de DBI-1.616". CPAN. 26 de septiembre de 2011.
- ^ "PEP 289 Python: Python Database API especificación v2.0".
- ^ "Las inyecciones SQL: Cómo no se atascan". El Codist. 08 de mayo de 2007. 01 de febrero de 2010.