OBJETIVO
Cada día se necesita procesar mayor
cantidad de datos y obtener de manera más rápida y precisa la información.
Muchos de los problemas de rendimiento se deben entre otras cosas al hardware,
al software, al motor de base de datos y por sobre todo al diseño, índices y
mala formulación de consultas SQL. En este documento nos centraremos en las
normas de programación en donde siguiendo algunas recomendaciones veremos que
se puede mejorar el tiempo de respuesta de nuestro motor de BD
significativamente.
NORMAS DE
PROGRAMACION T-SQL
En la instrucción de SELECT debe solo
recuperar lo necesario, nunca datos de más. Por otro lado nunca utilizar la
sentencia SELECT *, porque el gestor lee primero la estructura antes de
ejecutar la sentencia.
Seleccionar solo aquellos campos que se
necesiten, cada campo extra genera tiempo extra.
Escribir las consultas con estructura
ANSI y NO con estructuras T-SQL
Ejemplo estructura ANSI
SELECT <Campo1>, <Campo2>
FROM <Nombre Tabla1> INNER JOIN <Nombre Tabla2> ON
<PK_TBL1> = <FK_Tbl2>
WHERE <Condición>
Ejemplo estructura T-SQL
SELECT <Campo1>, <Campo2>
FROM <Nombre Tabla1>, <Nombre Tabla2> WHERE
<PK_Tbl1> = <FK_Tbl2> and
<Condición>
Dado lo anterior, para realizar las
relaciones entre las tablas, se deben utilizar las instrucciones:
- INNER JOIN
- LEFT JOIN
- RIGHT JOIN
- CROSS JOIN
Si se utiliza varias tablas en la
consulta, hay que especificar siempre a que tabla pertenece cada campo. Esto
ahorra al gestor el tiempo de localizar a que tabla pertenece el campo.
Ejemplo
En lugar de:
SELECT Nombre, Factura
FROM Clientes inner join Facturacion on
IdCliente =IdClienteFacturado
Usar:
SELECT Clientes.Nombre,
Facturacion.Factura
FROM Clientes inner join Facturacion on
Clientes.IdCliente =
Facturacion.IdClienteFacturado
No utilizar frecuentemente la cláusula LIKE,
en el caso de utilizarla es recomendable realizar Like ‘m%’ que %m, por
ejemplo, ya que en el primer caso, el plan de ejecución de SQL determina y
recorre el registro por el índice que contiene la tabla, siempre y cuando el índice
exista.
Utilizar en vez de la cláusula IN la
cláusula BETWEEN, cuando sea posible en la instrucción
WHERE.
Utilizar lo menos posible las cláusulas
ANY, SOME, IN (SELECT), NOT, IS NULL, != , <>, !>, !<,
NOT EXISTS, NOT IN, NOT LIKE, LIKE ‘%ab.
No utilizar tablas temporales públicas.
En el caso que se utilicen tablas temporales locales en algún procedimiento,
estas siempre se deben eliminar al terminar de utilizarse en el procedimiento
en cuestión, de igual modo antes de crear alguna tabla temporal local, siempre
se debe ver la opción de utilizar variables tipo tabla como prioridad.
Utilizar la instrucción TOP si necesita
una cantidad limitada de filas.
La instrucción TOP nos devuelve la
cantidad de filas que nosotros le especifiquemos.
Ejemplo
Esto nos devolverá las primeras 10 filas
de la tabla “<Nombre Tabla1>”:
SELECT TOP 10 <Campo1> FROM
<Nombre Tabla1>
Usar la cláusula EXISTS en lugar de la
cláusula IN. La cláusula EXISTS es ligeramente más rápida.
Utilizar la cláusula EXISTS en vez de la
sentencia SELECT Count(*) FROM…, esta práctica generalmente se realiza con la
instrucción IF.
En el caso de que se esté utilizando la
cláusula EXIST de este modo:
SELECT <Campo1> FROM <Nombre
Tabla1>
WHERE EXISTS (SELECT * FROM <Nombre
Tabla2>)
Lo óptimo es hacer lo siguiente:
SELECT <Campo1> FROM <Nombre
Tabla1>
WHERE EXISTS (SELECT TOP 1 <Campo1>
FROM <Nombre Tabla2>)
La misión de la función EXIST en este
caso es corroborar si existe o no X valor, por esta misma razón lo optimo es
hacerlo solo llamando un campo y haciendo un TOP 1 sobre la consulta anidada ya
que de esta manera no se pierde el sentido de la consulta porque el efecto será
el mismo. De esta manera hacemos que la consulta sea mucho más liviana.
Evitar usar la instrucción UNION, a menos
que este eliminado filas duplicadas.
No utilizar la instrucción ROUND, LOWER,
UPPER, SUBSTRING en el WHERE.
Reemplazar Count(*) por Count(1) o
Count(<Nombre del campo>)
No Utilizar WITH NOLOCK o WITH ROWLOCK
porque esta sentencia puede leer la tabla aun cuando tenga transacciones
pendientes (update, delete e insert), por ende podría mostrarse y leerse
información que puede no sea real.
Definir variables con el tipo de datos
adecuados al dato a almacenar. Porque si no es así, podría haber errores al
almacenar algún dato, o al intentar hacer alguna operación con el dato en
cuestión.
Se debe colocar el esquema
correspondiente a la tabla que se defina.
Ejemplo
BASE.. TABLA
Reemplazar por
BASE.dbo.TABLA
Como buena práctica también se anima a
incluir en el código la instrucción SET NOCOUNT ON, ya que esta instrucción evita que se devuelva el mensaje que muestra el recuento del número de
filas afectadas por una instrucción o un procedimiento almacenado como parte
del conjunto de resultados. Si se establece SET NOCOUNT en ON, no se devuelve el recuento. Cuando
SET NOCOUNT es OFF, sí se devuelve ese número.
No utilizar ejecuciones de código
DINAMICO, ya que con esta forma no se sabe si la sintaxis es correcta hasta
cuando se ejecutan los procesos, El Servidor tiene que compilar y luego
ejecutar.
Utilizar CASE de tal modo de suplir la
necesidad de usar código dinámico. La sentencia CASE se utiliza para brindar un
tipo de lógica "si-entonces-otro" para SQL.
Indentar u ordenar el código fuente del
programa para mejorar la legibilidad por parte de los programadores.
CURSORES
Evitar utilizar Cursores sin antes ver la
posibilidad de que la misma operación se realice por medio de sentencia SQL.
Utilizar el tipo de datos Table en vez de
cursores, pero solo cuando estas tengan pocos datos.
Ejemplo
Declare @VarTable TABLE (<Nombre
Campo1> <Tipo de dato>, <Nombre Campo…n> <Tipo de dato>)
Solo se aceptaran declaraciones cursores
para aquellos que apunten a tablas temporales, dentro de todo lo malo. Y además
que contengan la siguiente estructura.
Solo lectura (Read_Only)
Solo de una dirección de lectura.
(Fast_Forward )
Ejemplo
DECLARE objects_cursor CURSOR LOCAL
FAST_FORWARD READ_ONLY FOR
En el caso de que en un IF venga
lo siguiente:
IF (SELECT COUNT (1) FROM <Nombre
Tabla1>) > 0 …
Lo
óptimo es hacer lo siguiente:
IF EXIST (SELECT <Campo1> FROM <Nombre
Tabla1>)…
Este método es mucho más rápido ya que el
primero cuenta todas las filas para poder traer un resultado, mientras que la
segunda opción busca de inmediato si existe o no alguna fila para así seguir
efectuando la consulta formulada.
Me sirvio mucho tu articulo... saludos!
ResponderEliminarMuy buena!
ResponderEliminar;)
EliminarBuena informacion gracias
ResponderEliminarExcelente...Muchas gracias.
ResponderEliminarExcelente...Muchas gracias.
ResponderEliminarBuen aporte, ahora el tema es poner en practica con BDD pequeñas y grandes, para poder visualizar la diferencia.
ResponderEliminarBuenas! Buen artículo. Algo que estaría bueno aclarar con WITH (NOLOCK) es que en buena cantidad de ocasiones es recomendable hasta obligatorio usarlo. Por ejemplo en un proceso batch o cuando no necesitamos datos actualizados, es recomendable usarlo ya que no necesitamos las últimas transacciones. Diferente cuando necesitamos que la consulta nos traiga hasta el último dato disponible. Saludos
ResponderEliminarBuenas Tardes, ¿si no se debe usar NOT IN porque sentencia se puede reemplazar?
ResponderEliminar