Anuncios en tutorial de programación PLSQL

jueves, 18 de enero de 2018

Problemas con los triggers SQL

Programador PL/SQL en la camaMucha gente piensa que los triggers PL/SQL son una de las más potentes herramientas de las bases de datos Oracle. De hecho lo son, pero existen dos razones fundamentales por las que, personalmente, trato de evitar la utilización de triggers a la hora de implementar mis proyectos en PL/SQL.

Problemas de mantenimiento


A largo plazo, la utilización de triggers suele causar grandes dolores de cabeza a la hora de pensar en el mantenimiento. Al ser piezas del código que sólo ocurren como consecuencia de que se ha realizado otra operación, es muy frecuente que la gente se olvide de que los triggers están allí, y revisar el código pensando en todas las piezas de la base de datos que pueden afectarle, se hace poco menos que imposible.

Este problema es muy sencillo de comprender. Una persona experta en PL/SQL que no conoce una aplicación realizada en código PL/SQL y SQL, puede comprender fácilmente lo que realiza un procedimiento almacenado, pero si nuestro sistema utiliza triggers de manera rutinaria, entonces ese procedimiento puede desencadenar centenares de otro tipo de procesos y cambios en la base de datos que no son detectables a simple vista.

En conclusión, los triggers hacen que la comprensión de un sistema sea complicada, causan que su mantenimiento sea más difícil de lo normal y crean confusión al permanecer ocultos en el esquema la base de datos. Mucha gente considera que los triggers son como sentencias DDL y que, al igual que no hay necesidad de revisar una sentencia CREATE TABLE, tampoco hay necesidad de revisar el código de un trigger PL/SQL. En realidad, los triggers son subrutinas que son llamadas una y otra vez, cuyo código debe revisarse de igual manera que se revisan paquetes y procedimientos almacenados.

Uso incorrecto de los triggers


En muchos casos de los que yo he analizado, los triggers PL/SQL se han implementado de forma incorrecta. El código de los triggers suele incluir enormes errores que el programador no fue capaz de prever o anticipar. Veamos algunos ejemplos de este tipo de implementaciones incorrectas.

En alguna ocasión me he encontrado con triggers que realizan operaciones como esta:

:new.nombre_completo := 
:new.nombre||' '||:new.apellidos;

Lo primero que se me viene a la cabeza al ver una línea de código como la de arriba, es que la columna nombre_completo debería ser una columna de una vista (view) o, en Oracle 11g, una columna virtual. La columna nombre_completo es el resultado de una función trivial, con casi ningún coste de procesamiento y que, de ser necesario, podría hasta ser indexada. No existe ninguna razón para almacenar el resultado de la función en la tabla física.

Además, imaginemos que por alguna razón queremos cambiar el valor de la columna nombre_completo para algunos registros, simplemente el trigger no nos dejará hacerlo y, si no conocemos la existencia del mismo, nos preguntaremos una y mil veces por qué el campo no se actualiza al ejecutar el comando UPDATE. El trigger creará, cuando menos, confusión, y, con suerte, nos daremos cuenta de su existencia y de que debemos deshabilitarlo para poder realizar la deseada actualización del campo.

Otro de los usos incorrectos de los triggers es utilizarlos para enviar emails a los usuarios cuando se inserta o se actualiza un registro de una tabla. Veamos el siguiente trigger:

SQL> CREATE TRIGGER enviar_correo
2   AFTER INSERT ON pedidos
3   FOR EACH ROW
4   BEGIN
5   UTL_MAIL.send
6   (sender=>'app@miempresa.com',
7   recipients=>'pedidos@miempresa.com',
8   subject=>'Nuevo pedido '||:new.num_pedido,
9   message=>'Nuevo pedido recibido');
10  END;
11  /

Trigger created.

El trigger es sintácticamente correcto, compilará sin problemas y, si se inserta un nuevo pedido en la tabla "pedidos", nuestros usuarios recibirán un email indicándoselo. Sin embargo, el trigger tiene un grave problema. Alguien se ha preguntado qué ocurrirá si insertamos cien registros en la mencionada tabla y, por cualquier razón, decidimos deshacer las inserciones ejecutando el comando ROLLBACK. Pues simplemente lo que ocurrirá es que habremos enviado cien emails a los usuarios indicándoles que existen cien nuevos pedidos que en realidad no existen.

En este sentido conviene señalar que, para que este tipo de situaciones ocurran, no es necesario que uno mismo invoque el ROLLBACK, sino que continuamente la base de datos Oracle deshace operaciones INSERT, UPDATE, MERGE o DELETE, sin necesidad de que uno se lo indique personalmente.

Podemos decir que prácticamente cualquier trigger PL/SQL que llame a funciones UTL_ (como UTL_FILE, UTL_HTTP, UTL_MAIL, UTL_SMTP, UTL_TCP, etcétera) estará incorrectamente implementado. En conclusión, con los triggers no se debe realizar ninguna operación que no pueda ser deshecha con posterioridad.

Los triggers también pueden causar problemas cuando los programadores no entienden debidamente una de las características más interesantes de las bases de datos Oracle, el hecho de que las lecturas no bloquean las escrituras, y de que las escrituras no bloquean las lecturas. Esto se torna especialmente crítico cuando los triggers se utilizan para forzar que se cumpla alguna regla determinada. Todo esto será tema de otro artículo posterior.

4 comentarios:

JoseTE dijo...

jajajaja, muy buena apreciación la de los mails que se envian en un trigger! los triggers son para lo que son! para casi nada! ;)

Pepelu dijo...

Hola Meta, he procedido a borrar tu mensaje porque es demasiado largo y lleno de códigos que no es capaz de interpretar blogger. Si quieres puedes enviarme un email a pepelublog[arroba]gmail[punto]com.

David Alejandro dijo...

los triggers son para lo que son! para casi nada! ;)

jajajajaj :) buenisimo saludos la web esta de lujo sigan asi...

. dijo...

Muy buen punto de vista hermano... saludos desde panama, soy estudiante y aspiro a ser DBA... mi mail leggons28 (@) arroba gmail dot (.) com jajaja como lo pones.... Saluuuuuuudooosss