No usar el prefijo sp_al crear store procedure

Cualquier procedimientos almacenados con el prefijo ‘sp_’ primero se busca en la base de datos maestro en lugar de la que se ha creado. Esto provocará un retraso en el procedimiento almacenado.

Evaluar el uso de DISTINCT

Sólo debe usarse si sabemos que la query puede devolver duplicados, y además esto puede provocar un mal funcionamiento de la aplicación que hace uso de los datos.

La sentencia DISTINCT genera una gran cantidad de trabajo extra a SQL Server debido a que consume muchos recursos que son necesarios para otras queries que sean lanzadas dentro de la base de datos. Sólo se debe usar si es necesario.

Devolver los datos que se necesitan usando TOP

Para evitar en la aplicación de forma sencilla el retorno de cientos de registros o incluso miles es posible usar el operador TOP con una sentencia SELECT. De este modo se puede  ayuda a mejorar el rendimiento. ejemplo:

SELECT TOP 100 fname, lname FROM customers
WHERE state = ‘mo’

Esta query limita los resultados a las 100 primeras filas, incluso si el criterio del WHERE de devuelve 10000 registros.

El operador TOP también permite seleccionar porcentajes, tal y como indica el siguiente ejemplo:

SELECT TOP 10 PERCENT fname, lname FROM customers
WHERE state = ‘mo’

Uso de SET ROWCOUNT

El resultado de SET ROWCOUNT es el mismo que TOP, pero en algunos casos puede tener peor rendimiento cuando se trata con listas no ordenadas, por ello es preferible el uso de TOP.

Uso de operadores en el WHERE

Otro aspecto importante de cara a mejorar el rendimiento de las queries, es tener en consideración que operadores dentro de la clausula WHERE tienen mejor rendimiento, a continuación se detalla una lista ordenada de mejor a peor rendimiento:

  1. =
  2. >, >=, <, <=
  3. LIKE
  4. <>

Además de esto, existen otros criterios que son también importantes a la hora de elaborar la condición de cualquier Query. Estas consideraciones son relativas a que ciertos operadores pueden prestarse a tener mejor rendimiento según se usen, a continuación detallamos estos casos, ordenados de mayor a peor rendimiento:

  1. Un literal único en lugar de varios usado al lado de un operador
  2. Un nombre de columna o de parámetro al lado de un operador
  3. Una expresión multi-operando al lado de un operador
  4. Un número único exacto al lado de un operador
  5. Un número único no exacto al lado de un operador (date, time)
  6. Datos de caracteres, Null

En el caso de haber varias expresiones dentro del WHERE, no se agiliza el rendimiento por ordenarlos, excepto en algunos casos.

Uso de NOT IN

En el caso que tengamos que hacer uso del comando NOT IN tendremos que tener especial cuidado en su uso ya que posee un mal rendimiento ya que obliga al SQL Server Optmizer a realizar un SCAN, en su lugar mejor utilizaremos la siguientes opciones ordenadas de mejor a peor rendimiento:

  1. Usar EXISTS o NOT EXISTS
  2. Usar IN
  3. Realizar un LEFT OUTER JOIN y chequear por una condición NULL

Cuando exista la posibilidad de elegir entre IN o EXISTS utilizaremos siempre EXISTS, ya que tiene mejor rendimiento.

Mejores prácticas en el uso de LIKE

En el caso del comando LIKE es necesario entender que hay maneras más optimas en el uso de dicho comando. En el caso que nos trata del comando LIKE debemos en la medida de los posible usar una “leading character” esto es un carácter diferente de un “wildcard” (%,*, etc…).

Por ejemplo la query LIKE ‘%m’ tiene peor rendimiento que LIKE ‘m%’ ya que en el segundo caso (más optimo rendimiento).

Insercción de datos binarios de gran tamaño

Si nuestra aplicación necesita inserta insertar datos binarios de gran tamaño en una columna de datos, se debe realizar en primer lugar a través de un Store Procedure y no usar nunca una sentencia INSERT dentro de nuestra aplicación.

LA razón es ue la aplicación debe primero convertir los datos binarios en una cadena de caracteres (lo que hace doblar su tamaño incrementando el tráfico de red y llevando más tiempo) antes de que pueda ser enviada al servidor. Y cuando el servidor recibe la cadena de caracteres, tiene que convertirla de nuevo a datos binarios (llevandose aún más tiempo que en la primera conversión).

El uso de Store Procedures evita todo esto ya que la actividad ocurre en el servidor SQL Server y los datos transmitidos a través de la red son menores.

Concatenación ANDs

Si existe una cláusula WHERE que incluye expresiones conectadas por dos o más operadores AND, SQL Server evaluará desde la izquierda hacia la derecha en el orden que hayan sido escritas. Esto asume que no se hayan usado paréntesis para cambiar el orden de la ejecución. Por esta razón se debe considerar lo siguiente cuando usemos el operador AND:

  1. Localizaremos la expresión menos probable de suceder y la pondremos en primer lugar de la expresión AND. De este modo si una expresión AND es falsa la cláusula finalizará inmediatamente ahorrando tiempo
  2. Si ambas partes de una expresión AND son iguales o tienen igual peso, y son falsas, pondremos la menos compleja primero. De este modo si es falsa la expresión se realizará menos trabajo para evaluar la expresión.

Uso de ORDER BY

Usaremos ORDER BY en las QUERIES que lancemos sólo si es absolutamente indispensable, es decir, que si es posible realizar la ordenación en el lado del cliente siempre será mejor que realizarla desde el lado del servidor SQL Server.

En el caso que sea absolutamente necesario realizar la ordenación en el lado del servidor SQL Server, deberemos atender a las siguientes recomendaciones:

  1. Mantener el número de filas a ordenar al mínimo, haciendo esto mediante la devolución de aquellas filas que son absolutamente necesarias.
  2. Mantener el número de columnas a ordenar al mínimo. En otras palabras, no ordenar columnas no rqueridas.
  3. Mantener el ancho (tamaño físico) de las columnas a ordenar al mínimo
  4. Ordenar columnas con tipos de datos númericos en lugar de tipos de datos carácter

No usar el comando GROUP BY sin una función de agregación

La cláusula GROUP BY puede usarse con o sin una función de agregación. Pero si queremos obtener un mejor rendimiento, no usaremos la cláusula GROUP BY sin una función de agregación. Esto es porque produce el mismo resultado usar DISTINCT y es más rápido. Veamos un ejemplo:

USE Northwind
SELECT OrderID
FROM [Order Details]
WHERE UnitPrice > 10
GROUP BY OrderID

O

USE Northwind
SELECT DISTINCT OrderID
FROM [Order Details]
WHERE UnitPrice > 10

Ambas QUERIES dan el mismo resultado, pero la segunda obtendrá mejor rendimiento, ya que usa menos recursos.

¿Cómo acelerar la cláusula GROUP BY?

Para acelerar el uso de la cláusula GROUP BY debemos seguir las siguientes recomendaciones:

  1. Mantener el número de fílas a devolver por la QUERY tan pequeño como sea posible
  2. Mantener el número de agrupaciones tan limitado como sea posible
  3. No agrupar columnas redundantes
  4. Si hay un JOIN en la misma SELECT que tiene un GROUP BY, intentar reescribir la QUERY usado una SUBQUERY en lugar de usar un JOIN. Si es posible hacer esto, el rendimiento sera major. Si se tiene que usar un JOIN, intentaremos hacer el GROUP BY por columna desde la misma tabla que la columna o columnas sobre la cual la se usa la función.

Consideraremos el añadir un ORDER BY a la SELECT que ordena por la misma columna que el GROUP BY. Eso puede producir que el GROUP BY tenga mejor rendimiento.

DERIVED TABLES en lugar de TEMPORARY TABLES

En lugar de usar tablas temporales, usaremos tablas derivadas para mejorar el rendimiento de nuestra QUERY. Esto funciona de la siguiente forma:

SELECT num_Customer, dt_Date FROM (SELECT num_Customer, dt_Date, nom_Customer FROM Customers)

Con este tipo de tablas mejoramos el rendimiento de nuestra QUERY ya que se producen menos operaciones de I/O sobre el servidor.

Comprobar la existencia de un registro en una tabla

Si necesitamos verificar si un registro existe en una tabla no usaremos nunca SELECT COUNT (*) para identificarla ya que es muy ineficiente y utiliza recursos de servidor de forma masiva.

En su lugar la sentencia Transact-SQL IF EXISTS para determinar si el registro en cuestión existe que es mucho más eficiente. Por ejemplo:

Usando SELECT COUNT (*):

IF (SELECT COUNT(*) FROM table_name WHERE column_name = ‘xxx’)

Usando IF EXISTS (mucho más rápido):

IF EXISTS (SELECT * FROM table_name WHERE column_name = ‘xxx’)

La razón por la cual IF EXISTS es más rápido que SELECT COUNT (*) es porque en el momento que dicha QUERY encuentra el registro finaliza inmediatamente, mientras que COUNT(*) debe contar todas las filas.