25 oct 2018

Integridad de los datos en SQL Server con CHECKSUM

Uno de los requerimientos importantes son la integridad de los datos, es necesario garantizar que ciertos datos queden fijos después de algún proceso y solo se pueden modificar mediante permisos especiales o un proceso determinado.

Es posible detectar si cambian los datos incluso por un programador que tiene acceso a línea de comandos para escribir sentencias Transact SQL usando la función CHECKSUM de SQL Server. La función CHECKSUM de SQL server devuelve un valor (hash) resultado de aplicar un algoritmo a los datos especificados (columnas). Entonces, basta calcular el CHECKSUM de las columnas que se desea validar que no sean alteradas y posteriormente comparar el valor de esta columna con el nuevo calculo del CHECKSUM, si estos son diferentes significa que fueron alterados.

El video que muestro a continuación da un ejemplo puntual del uso de esta función:





* SQL Server sugiere usar la función HASHBYTES para disminuir la probabilidad de colisión (dos datos distintos dan por resultado el mismo valor hash). En lo particular prefiero CHECKSUM por su facilidad de manejo de valor regresado, el cual es un int, mientras que HASHBYTES regresa un varbinary. Además de que no es importante si existe alguna colisión en los CHECKSUM devueltos. Considerar que el tipo int de Transact es un entero de 4 bytes, el cual tiene un rango de -2^31 a 2^31, esto significa un rango de +4 mil millones de combinaciones, lo cual es bastante bueno.

Optimizando para velocidad con las relaciones uno a uno

Debo aclarar que las relaciones uno a uno, no son una forma 'normal', esto significa que durante un proceso de normalización deberían desaparecer las relaciones uno a uno... excepto cuando se 'desnormaliza' conscientemente por asi convenir, como es este caso.


Problema: Tengo una aplicación de ventas, donde en últimos tiempos el proceso de seleccionar las facturas pendientes de pago se ralentizo considerablemente, llegando hasta un par de minutos. Este proceso consta de una simple consulta de la forma:


Select IDVenta, Fecha, NoDoc, NoDoc, Saldo, Total From TbaVenta Where  (IDCliente=12345) And ((TipoDoc='F') Or (TipoDoc='R') Or (TipoDoc='N') ) And (Afecto<>0) And (Saldo>0)

Esto es, selecciona todas las facturas del cliente 12345 que son Facturas, Remisiones o Notas afectadas y que tiene Saldo.


La columna IDSaldo de la tabla TbaVenta esta indexada, no así las columnas TipoDoc, Afecto y Saldo


En un análisis superficial supuse que si indexaba la columna Saldo el rendimiento mejoraría y asi fue, bajando de 100 hasta 5 segs en mi servidor de pruebas. No conforme con eso busque una alternativa y recurri a un viejo truco... una relación uno a uno, logrando reducir a casi 1/3 del tiempo de ejecución respecto al proceso de indexación anterior, como lo muestro en el video siguiente:






Y aquí tenemos una razón para usar una relación uno a uno!