Você está na página 1de 7

MEJORES PRCTICAS DE DESARROLLO

A continuacin se detallan algunas guas de programacin y mejores prcticas para SQL Server 2000, teniendo en mente la calidad, desempeo y capacidad de mantenimiento de la base de datos. Esta lista se ira actualizando constantemente de manera que sea de utilidad para todos: Establecer una poltica de nomenclatura de base de datos, estandarizarla en la compaa y seguirla. Esto ayudara a que el cdigo sea legible y entendible. Asegurarse de normalizar la base de datos al menos en Tercera Forma Normal (3NF). Al mismo tiempo, no hay que comprometer el desempeo de las consultas. Un poco de desnormalizacin ayudara a que las consultas se desempeen rpido. Escribir generosamente comentarios en los stored procedures, triggers y batches de SQL cuando algo no sea muy obvio. Esto ayudara a otros programadores a entender claramente el cdigo. No hay que preocuparse por la longitud de los comentarios ya que no impacta en el desempeo. No utilizar SELECT * en las consultas. Hay que escribir siempre los nombres de las columnas requeridas despus del SELECT, por ejemplo:
SELECT CustomerID, CustomerFirstName, City

Esta tcnica ayuda a reducir los accesos a disco (I/O) y mejora el desempeo. Evitar el uso de cursores de lado del servidor lo ms posible. Siempre utilice un enfoque basado en conjuntos en lugar de uno de procedimiento al momento de accesar y manipular datos. A menudo los cursores pueden ser evitados utilizando sentencias SELECT. Si un cursor es inevitable, en su defecto se recomienda utilizar un ciclo WHILE ya que es mucho ms rpido que un cursor. Pero para reemplazar el uso de un cursor por un ciclo WHILE se necesitara una columna (ya sea llave primaria o nica) para identificar cada rengln exclusivamente. Evitar la creacin de tablas temporales durante el proceso de datos lo ms posible ya que el crear tablas temporales implica mayor acceso a disco (I/O). Considerar el uso de otras tcnicas como vistas, variables de tipo tabla, o tablas derivadas, en lugar de tablas temporales. Evitar el uso de caracteres comodn al inicio de una palabra al momento de realizar una bsqueda utilizando LIKE ya que esto genera un barrido de ndice (index scan) lo cual va en contra del propsito de un ndice. Como ejemplo, la siguiente sentencia genera un index scan, mientras que la segunda genera un index seek:
SELECT LocationID FROM Locations WHERE Specialities LIKE '%pples' SELECT LocationID FROM Locations WHERE Specialities LIKE 'A%s'

Tambin hay que evitar las bsquedas utilizando operadores de desigualdad (<> y NOT) ya que generan index scan y table scan.

Utilizar tablas derivadas cuando sea posible ya que tienen mejor desempeo. Como ejemplo, con el siguiente query se obtiene el segundo salario mas alto de la tabla Employees:

SELECT FROM WHERE ( SELECT FROM ORDER )

MIN(Salary) Employees EmpID IN TOP 2 EmpID Employees BY Salary Desc

El mismo query puede ser reescrito utilizando una tabla derivada, como se muestra en seguida, y adems se desempea el doble de rpido que el query anterior:
SELECT MIN(Salary) FROM ( SELECT TOP 2 Salary FROM Employees ORDER BY Salary DESC ) AS A

Este es solo un ejemplo, el resultado puede variar en diferentes escenarios dependiendo del diseo de la base de datos, ndices, volumen de datos, etc. Por eso, lo ms recomendable es probar todas las posibles formas en las que se puede escribir un query y seleccionar la ms eficiente. Tener siempre en mente el desempeo cuando se esta realizando algn diseo de base de datos. Realmente no se puede afinar el desempeo mas tarde, cuando el diseo ya se implemento en produccin, ya que puede implicar reconstruir tablas e ndices, reescribir querys, etc. Se recomienda utilizar el plan de ejecucin grafico del Query Analyzer o los comandos SHOWPLAN_TEXT o SHOWPLAN_ALL para analizar los querys. Hay que asegurarse de que los querys hagan index seek en lugar de index scan o table scan ya que ambos impactan de mal manera en el desempeo y deben evitarse lo ms posible. Hay que elegir los ndices correctos en las columnas correctas. Poner siempre como prefijo a los nombres de las tablas el nombre del propietario (owners name) ya que esto mejora la legibilidad y evita cualquier confusin innecesaria. Incluso en los Books Online de SQL Server se menciona que el hacer uso de esta prctica ayuda a la reutilizacin del plan de ejecucin, aumentando aun ms el desempeo. Utilizar SET NOCOUNT ON al inicio de cualquier batch de SQL, stored procedures y triggers en produccin ya que esto elimina mensajes como '(1 row(s) affected)' despus de ejecutar sentencias como INSERT, UPDATE, DELETE y SELECT. Esto mejora el desempeo de los stored procedures ya que se reduce el trfico de red. Utilizar el estndar ANSI ms legible para las clusulas Join en lugar del estilo ms comn. Utilizando la sintaxis ANSI Join la clusula WHERE es utilizada solamente para filtrar datos. Mientras con el otro estilo de Joins la clusula WHERE maneja tanto la condicin del Join y el filtrado de datos. Como ejemplo, el primer query utiliza la sintaxis anterior del Join y el segundo query utiliza la nueva sintaxis ANSI Join:
SELECT a.au_id, t.title

FROM WHERE AND AND

titles t, authors a, titleauthor ta a.au_id = ta.au_id ta.title_id = t.title_id t.title LIKE '%Computer%'

SELECT a.au_id, t.title FROM authors a INNER JOIN titleauthor ta ON a.au_id = ta.au_id INNER JOIN titles t ON ta.title_id = t.title_id WHERE t.title LIKE '%Computer%'

No utilizar el prefijo sp_ en los nombres de stored procedures. El prefijo sp_ esta reservado para stored procedures del sistema. Cuando SQL Server se topa con un nombre de stored procedure que inicia con sp_ primero intenta localizarlo en la base de datos master, en seguida busca si tiene algn calificador (base de datos, propietario), luego intenta con dbo como propietario. As que realmente se puede ahorrar tiempo en localizar el stored procedure evitando usar el prefijo sp_. Las vistas son usadas generalmente para mostrar datos especficos a usuarios especficos basados en sus intereses. Tambin son usadas para restringir acceso a las tablas base otorgando permisos nicamente a las vistas. Otro uso que se les da alas vistas es para simplificar los querys. Se recomienda incorporar a las vistas los clculos y Joins que sean frecuentes, requeridos o complicados para no repetirlos en todos los querys. En lugar de eso, solo se selecciona la vista. Utilizar Tipos de Datos Definidos si una columna en particular se repite en muchas tablas, de manera que el tipo de dato de esa columna sea consistente en todas las tablas donde se utilice. Evitar el realizar querys o manipular datos directamente desde el front-end de las aplicaciones mediante sentencias SELECT, INSERT, UPDATE o DELETE. En lugar de eso, se recomienda crear stored procedures que sean accesados desde el sistema. Esto mantiene limpio y consistente el acceso a datos desde cualquier mdulo o aplicacin, y al mismo tiempo se centraliza la lgica de negocio. Utilizar el tipo de dato CHAR en una columna nicamente cuando la columna sea no nulable. Si una columna de tipo CHAR es nulable, es tratada como columna de longitud fija en SQL Server 7.0 en adelante. Por ejemplo, un CHAR(100), cuando sea nulo, va a consumir hasta 100 bytes, lo cual es un desperdicio de espacio. En este caso se recomienda utilizar VARCHAR(100). Claro, las columnas de longitud variable elevan un poco ms el procesamiento que las de longitud fija. Por lo tanto, se debe de escoger cuidadosamente entre usar CHAR o VARCHAR dependiendo de la longitud del dato que se desea almacenar. Evitar el uso de sentencias dinmicas de SQL lo ms posible. SQL dinmico tiende a ser ms lento que SQL esttico ya que SQL Server deber generar un plan de ejecucin cada vez que el cdigo sea ejecutado. Las sentencias IF y CASE son tiles para evitar SQL dinmico. Otra desventaja de usar SQL dinmico es que requiere que el usuario que ejecute el cdigo tenga permisos de acceso a todos los objetos que sean utilizados como tablas y vistas. Generalmente a los usuarios se les otorgan permisos de acceso a los stored procedures que hacen referencia a tablas, pero no directamente sobre stas. En este caso, el uso de SQL dinmico no funcionaria. Por ejemplo, en el siguiente escenario el usuario dSQLuser es agregado a la base de datos pubs y se le otorgan permisos sobre el stored procedure

dSQLproc. El stored procedure dSQLproc ejecuta un SELECT directo a la tabla titles y funciona sin ningn problema. La segunda sentencia ejecuta el mismo SELECT a la tabla titles usando SQL dinmico y falla mostrando el siguiente mensaje de error:
Server: Msg 229, Level 14, State 5, Line 1 SELECT permission denied on object 'titles', database 'pubs', owner 'dbo'.

Para reproducir el error anterior, utilice el siguiente cdigo:


sp_addlogin 'dSQLuser' GO sp_defaultdb 'dSQLuser', 'pubs' GO USE pubs GO sp_adduser 'dSQLUser', 'dSQLUser' GO CREATE PROCEDURE dbo.dSQLProc AS BEGIN SELECT * FROM titles WHERE title_id = 'BU1032' --This works DECLARE @str CHAR(100) SET @str = 'SELECT * FROM titles WHERE title_id = ''BU1032''' EXEC (@str) --This fails END GO GRANT EXEC ON dSQLProc TO dSQLuser GO

Ejecute el stored procedure dSQLproc en la base de datos pubs con el usuario dSQLuser para ver el resultado. Considerar lo siguiente antes de usar la propiedad IDENTITY para generar llaves primarias. IDENTITY es una propiedad muy especfica de SQL Server la cual puede ocasionar problemas al momento de querer portar la base de datos a otro RDBMS. Las columnas IDENTITY tienen otros problemas inherentes. Por ejemplo, las columnas IDENTITY pueden en algn momento quedarse sin nmeros dependiendo del tipo de dato seleccionado; los nmeros no pueden ser reutilizados en automtico, despus de haber borrado registros; adems, la replicacin y las columnas IDENTITY no siempre se relacionan bien. Una opcin seria utilizar un algoritmo para generar una llave primaria desde el front-end o desde algn stored procedure. De cualquier manera podran existir problemas generando llaves primarias en base a algoritmos, como concurrencia al momento de generar la llave o que se lleguen a agotar los nmeros. Se recomienda considerar ambas opciones y seleccionar aquella que mejor se adapte a las necesidades. Minimizar el uso de nulos ya que comnmente generan confusin en el front-end de las aplicaciones, a menos que las aplicaciones sean codificadas de manera que los eliminen o los conviertan en otro valor. Cualquier expresin que maneje nulos arrojar como resultado un valor nulo. Las funciones ISNULL y COALESCE son de ayuda en el manejo de valores nulos.

Por ejemplo, considerando la siguiente tabla Customers la cual almacena nombres de clientes en donde el segundo nombre puede ser nulo:
CREATE TABLE dbo.Customers ( FirstName varchar(20), MiddleName varchar(20), LastName varchar(20) )

Ahora insertamos un registro en la tabla sin segundo nombre:


INSERT INTO Customers (FirstName, MiddleName, LastName) VALUES ('Tony',NULL,'Blair')

El siguiente SELECT retorna NULL en lugar del nombre del cliente:


SELECT FirstName + ' ' + MiddleName + ' ' + LastName FROM Customers

Para evitar este problema se utiliza ISNULL de la siguiente manera:


SELECT FirstName + ' ' + ISNULL(MiddleName,'') + LastName FROM Customers

Incluir siempre en los INSERT la lista de columnas. Esto ayuda a evitar problemas cuando cambie la estructura de la tabla (cuando se agrega o elimina una columna). Por ejemplo, considerando la siguiente tabla:
CREATE TABLE dbo.EuropeanCountries ( CountryID int PRIMARY KEY, CountryName varchar(25) )

Este es un INSERT sin lista de columnas que hasta el momento funciona sin problemas:
INSERT INTO EuropeanCountries VALUES (1, 'Ireland')

Ahora si agregamos una columna a la tabla:


ALTER TABLE EuropeanCountries ADD EuroSupport bit

Y ejecutamos el INSERT anterior, SQL Server nos arrojara el siguiente mensaje de error:
Server: Msg 213, Level 16, State 4, Line 1 Insert Error: Column name or number of supplied values does not match table definition.

Este problema se puede evitar agregando al INSERT la lista de columnas:


INSERT INTO EuropeanCountries (CountryID, CountryName) VALUES (1, 'England')

Llevar a cabo todas las validaciones de integridad referencial y de datos utilizando constraints (llaves forneas y check constraints) en lugar de triggers ya que es mucho ms rpido. Limitar el uso de triggers solamente para auditorias, tareas personalizadas, y validaciones que no puedan ser ejecutadas usando constraints. Las constraints nos ayudan a ahorrar tiempo

ya que no hay necesidad de escribir cdigo que realice esas validaciones dejando al RDBMS hacer todo el trabajo. Si la principal preocupacin es la portabilidad del back-end, se recomienda evitar la manipulacin de bits con T-SQL ya que es algo muy especfico de SQL Server. Adems, usar bitmaps para representar diferentes estados de una entidad en particular hace conflicto con las reglas de normalizacin. Agregar siempre el parmetro @Debug a los stored procedures. Este puede ser de tipo BIT. Cuando se le enve 1 a este parmetro se imprimirn resultados intermedios y contenidos de variables utilizando SELECT o PRINT, y cuando se le enve 0 no se imprimir nada. Esto ayuda a debuguear rpidamente los stored procedures ya que no ser necesario agregar y quitar sentencias SELECT o PRINT antes y despus de solucionar problemas. No llamar repetidamente funciones dentro de stored procedures, triggers, funciones y batches. Por ejemplo, si se necesita la longitud de una variable string en muchos lugares dentro de un stored procedure no es necesario llamar la funcin LEN cuando sea requerido, en lugar de eso, se recomiendo llamar la funcin LEN una sola vez y almacenar el resultado en una variable para su uso posterior. Asegurarse de que los stored procedures siempre retornen un valor indicando su estatus. Se recomienda estandarizar los valores de retorno que puede tener un stored procedures en caso de que se ejecute con xito o con errores. La sentencia RETURN se utiliza nicamente para retornar el estatus de la ejecucin, no para retornar datos. Si lo que se necesita es retornar datos, se recomienda parmetros de salida (OUTPUT). Si un stored procedure regresa siempre un solo registro como resultset, se recomienda utilizar parmetros de salida en lugar de sentencias SELECT ya que ADO maneja mucho mejor los parmetros de salida que los resultsets de sentencias SELECT. Se recomienda verificar siempre la variable global @@ERROR inmediatamente despus de ejecutar alguna sentencia de manipulacin de datos (como INSERT, UPDATE, o DELETE) de manera que se pueda realizar un rollback a la transaccin en caso de un error (la variable @@ERROR ser siempre mayor a 0 en caso de un error). Esto es importante ya que SQL Server por default no hace rollback a todos los cambios realizados dentro de una transaccin si una sentencia en particular falla. Este comportamiento puede ser modificado ejecutando SET XACT_ABORT ON. La variable @@ROWCOUNT tambin juega un papel importante al momento de determinar cuantos registros fueron afectados en la manipulacin de datos previa, y basndonos en eso se puede escoger entre realizar un commit o rollback a la transaccin. Para hacer ms legible las sentencias de SQL se recomienda empezar cada clusula en una nueva lnea e indentar cuando sea necesario. Este es un ejemplo:
SELECT title_id, title FROM titles WHERE title LIKE '%Computer%' AND title LIKE '%cook%'

Se recomienda no utilizar sentencias GOTO o en casos excepcionales con moderacin ya que el uso excesivo de esta tcnica puede ocasionar que el cdigo sea difcil de leer y de entender.

Usar variables en lugar de valores constantes dentro de querys mejora la legibilidad y capacidad de mantenimiento del cdigo. Considerando el siguiente ejemplo:
SELECT OrderID, OrderDate FROM Orders WHERE OrderStatus IN (5,6)

El mismo cdigo puede ser reescrito de una manera aun ms legible, en seguida se muestra como:
DECLARE @ORDER_DELIVERED, @ORDER_PENDING SELECT @ORDER_DELIVERED = 5, @ORDER_PENDING = 6

SELECT OrderID, OrderDate FROM Orders WHERE OrderStatus IN (@ORDER_DELIVERED, @ORDER_PENDING)

No se recomienda utilizar nmeros de columnas en la clusula ORDER BY. En el siguiente ejemplo, el segundo query es mas legible que el primero:
SELECT OrderID, OrderDate FROM Orders ORDER BY 2 SELECT OrderID, OrderDate FROM Orders ORDER BY OrderDate

Se recomienda parametrizar los querys utilizando el sp_executesql. Esto ayudara a que el optimizador de SQL Server almacene los planes de ejecucin y los reutilice cuando se ejecuten por segunda ocasin. Esta tcnica es mucho ms eficiente que utilizar EXECUTE.

Você também pode gostar