Anuncios en tutorial de programación PLSQL

miércoles, 31 de agosto de 2016

Cláusula DEFAULT para definición de columnas - Base de datos Oracle 12c

Las mejoras fundamentales que aporta la nueva cláusula DEFAULT de la versión 12c de las bases de datos Oracle para definición de las columnas: una significativa mejora del rendimiento y una mayor facilidad para inicializar los datos de los registros de una tabla, lo que al final implica menos líneas de código.

Cláusula DEFAULT

Supongamos que para una tabla concreta necesitamos que, cuando se inserta un nuevo registro, un campo determinado tome el valor de una secuencia. La forma en que implementaríamos este requerimiento en versiones anteriores a la 12c sería mediante un trigger PLSQL.

Veamos a continuación un ejemplo:
CREATE OR REPLACE TRIGGER trig_det_facturas
BEFORE INSERT ON detalle_facturas
FOR EACH ROW
BEGIN
     :new.det_factura_id := seq_det_facturas.nextval;
END;

Problemas de rendimiento y eficiencia


Pero los triggers, aunque sean tan sencillos como el del ejemplo, pueden afectar negativamente al rendimiento de la base de datos, sobre todo si a diario se tienen que insertar millones de registros en la tabla que necesita de dicho trigger.

Podemos incluso hacer una simple prueba, insertar un millón de registros en la tabla detalle_facturas, comprobar lo que tarda la base de datos en insertar dichos registros y, posteriormente, deshabilitar el trigger (ALTER TRIGGER trig_det_facturas DISABLE), volviendo a insertar el mismo número de registros. No debe sorprendernos que con el trigger habilitado el proceso de inserción dure más de cinco minutos, mientras que sin el trigger el tiempo sea solo de unos segundos.

Problemas de integridad de los datos


Además, el anterior trigger tiene un problema asociado. ¿Qué ocurriría si por algún motivo debemos ejecutar el siguiente código?
DELETE FROM detalle_facturas WHERE det_factura_id = 51;

INSERT INTO detalle_facturas
(det_factura_id, factura_id, num_linea, …)
VALUES (51, 20, 1, …);

Observaréis que nuestro trigger va a actualizar el campo det_factura_id, cuando realmente no deseamos que esto ocurra. Solo tenemos que ejecutar el siguiente comando y comprobar que no devolverá ningún registro, ya que no existirá ningún registro para el ID 51.
SELECT * FROM detalle_facturas WHERE det_factura_id = 51;

Esto nos obligará a actualizar el código de nuestro trigger de la siguiente manera:
CREATE OR REPLACE TRIGGER trig_det_facturas
BEFORE INSERT ON detalle_facturas
FOR EACH ROW
WHEN (new. det_factura_id IS NULL)
BEGIN
     :new.det_factura_id := seq_det_facturas.nextval;
END;

El caso es que desde la versión 12c disponemos de una solución mucho más adecuada para implementar la misma funcionalidad que nos aporta el trigger anterior.

Opciones de la cláusula DEFAULT para columnas


La versión 12c Oracle ofrece la posibilidad de utilizar la cláusula DEFAULT a la hora de definir las columnas de una tabla. De hecho es posible asignar a una columna el valor de una secuencia como valor por defecto. Algo tan simple como esto:
ALTER TABLE detalle_facturas
MODIFY det_factura_id DEFAULT seq_det_facturas.nextval;

Este cambio no sólo evita que tengamos que utilizar un trigger, sino que la inserción de un millón de registros pasará de tardar unos cuantos minutos a tardar tan sólo unos segundos.

Ahora supongamos que en la tabla detalle facturas se nos olvidó poner como obligatoria una determinada columna, por ejemplo, la fecha de creación. De tal manera que en nuestra tabla encontramos múltiples registros donde la columna fecha_creacion toma el valor no deseado de NULL. La cláusula DEFAUL nos ofrece una sencilla solución:
ALTER TABLE detalle_facturas
MODIFY fecha_creacion DEFAULT SYSDATE;

No obstante, ¿qué ocurre si alguna aplicación externa inserta registros en nuestra tabla de la siguiente manera?
INSERT INTO detalle_facturas
(det_factura_id, factura_id, num_linea, fecha_creacion, …)
VALUES (51, 20, 1, NULL, …);

Todavía nos encontraremos con registros en los que la columna fecha_creacion tomará el valor de NULL. No obstante, la cláusula DEFAULT nos da también la solución a este problema.
ALTER TABLE detalle_facturas
MODIFY fecha_creacion DEFAULT ON NULL SYSDATE;

No obstante, si sin realizar ningún cambio en los datos de la tabla intentamos ejecutar el comando anterior, esté nos va a generar el siguiente error:
ORA-02296: cannot enable () - null values found

Esto se debe a que la cláusula DEFAULT ON NULL automáticamente limita la columna a ser de tipo NOT NULL, por lo que primero tendremos que actualizar debidamente la columna fecha_creacion y después ya podremos ejecutar el comando ALTER TABLE sin problemas. Por ejemplo:
UPDATE detalle_facturas
SET fecha_creacion = NVL(fecha_factura,SYSDATE)
WHERE fecha_creacion IS NULL;

ALTER TABLE detalle_facturas
MODIFY fecha_creacion DEFAULT ON NULL SYSDATE;

En conclusión, si hemos actualizado la versión de nuestra base de datos Oracle a la 12c y sabemos que estamos utilizando triggers PLSQL para gestionar la inserción de valores por defecto, deberemos revisar el código y comprobar si dichos triggers pueden ser reemplazados por la nueva cláusula DEFAULT. Nuestra aplicación terminará con menos líneas de código pero sobre todo mejorará su rendimiento.

0 comentarios: