Son muchas las cosas que se hacen utilizando triggers que pueden hacerse
tambi�n utilizando el sistema de las reglas de
Postgres. Lo que actualmente no se puede
implementar a trav�s de reglas son algunos tipos de restricciones
(constraints). Es posible situar una regla cualificada que reescriba una
query a NOTHING si el valor de la columna no aparece en otra tabla, pero
entonces los datos son eliminados silenciosamente, y eso no es una buena
idea. Si se necesitan comprobaciones para valores v�lidos, y en el caso de
aparecer un valor inv�lido dar un mensaje de error, eso deber� hacerse por
ahora con un trigger.
Por otro lado, un trigger que se dispare a partir de una INSERT en una
vista puede hacer lo mismo que una regla, situar los datos en cualquier
otro sitio y suprimir la inserci�n en una vista. Pero no puede hacer lo
mismo en una UPDATE o una DELETE, poruqe no hay datos reales en la relaci�n
vista que puedan ser comprobados, y por ello el trigger nunca podr�a ser
llamado. S�lo una regla podr�a ayudarnos.
Para los tratamientos que podr�an implementarse de ambas formas, depender�
del uso de la base de datos cu�l sea la mejor. Un trigger se dispara para
cada fila afectada. Una regla manipula el �rbol de traducci�n o genera uno
adicional. De modo que si se manupulan muchas filas en una instrucci�n, una
regla ordenando una query adicional usualmente dar�a un mejor resultado que
un trigger que se llama para cada fila individual y deber� ejecutar sus
operaciones muchas veces.
Por ejemplo: hay dos tablas.
CREATE TABLE computer (
hostname text -- indexed
manufacturer text -- indexed
);
CREATE TABLE software (
software text, -- indexed
hostname text -- indexed
); |
Ambas tablas tienen muchos millares de filas y el �ndice sobre hostname es
�nico. La columna hostname contiene el nombre de dominio cualificado
completo del ordenador. La regla/trigger deber�a desencadenar el borrado de
filas de la tabla software que se refieran a un host borrado. Toda vez que
el trigger se llama para cada fila individual borrada de computer, se puede
usar la instrucci�n
DELETE FROM software WHERE hostname = $1; |
en un plan preparado y salvado, y pasar el hostname en el par�metro.
La regla deber�a ser escrita como
CREATE RULE computer_del AS ON DELETE TO computer
DO DELETE FROM software WHERE hostname = OLD.hostname; |
Veremos ahora en que se diferencian los dos tipos de delete. En el caso de
una
DELETE FROM computer WHERE hostname = 'mypc.local.net'; |
La tabla computer se revisa por �ndice (r�pido) y la query lanzada por el
trigger tambi�n deber�a ser un barrido de �ndice (r�pido tambi�n). La query
extra para la regla ser�a una
DELETE FROM software WHERE computer.hostname = 'mypc.local.net'
AND software.hostname = computer.hostname; |
Puesto que se han creado los �ndices apropiados, el optimizador crear� un
plan de
Nestloop
-> Index Scan using comp_hostidx on computer
-> Index Scan using soft_hostidx on software |
De modo que no habr�a mucha diferencia de velocidad entre la implementaci�n
del trigger y de la regla. Con la siguiente delete, queremos mostrar borrar
los 2000 ordenadores cuyo hostname empieza con 'old'. Hay dos posibles
queries para hacer eso. Una es
DELETE FROM computer WHERE hostname >= 'old'
AND hostname < 'ole' |
Donde el plan de ejecuci�n para la query de la regla ser�
Hash Join
-> Seq Scan on software
-> Hash
-> Index Scan using comp_hostidx on computer |
La otra query posible es
DELETE FROM computer WHERE hostname ~ '^old'; |
con un plan de ejecuci�n
Nestloop
-> Index Scan using comp_hostidx on computer
-> Index Scan using soft_hostidx on software |
Esto muestra que el optimizador no comprueba que la cualificaci�n sobre
hostname en computer tambi�n deber�a se utilizado para un barrido por
�ndice en software donde hay m�ltiples expresiones de cualificaci�n
combinadas con AND, que el hace en la versi�n regexp de la query. El
trigger ser� invocado una vez para cada una de los 2000 viejos ordenadores
que ser�n borrados, lo que dar� como resultado un barrido por �ndice sobre
computer y 2000 barridos por �ndice sobre software. La implementaci�n de la
regla lo har� con dos queries sobre �ndices. Y depender� del tama�o
promedio de la tabla software si la regla ser� m�s r�pida en una situaci�n
de barrido secuencial. 2000 ejecuciones de queries sobre el gestor SPI
toman su tiempo, incluso si todos los bloques del �ndice se encuentran en
la memor�a cach�.
La �ltima query que veremos es
DELETE FROM computer WHERE manufacurer = 'bim'; |
De nuevo esto deber�a dar como resultado muchoas filas para borrar de
computer. Por ello el trigger disparar� de nuevo muchas queries sobre el
ejecutor. Pero el plan de las reglas ser� de nuevo un bucle anidado sobre
dos barridos de �ndice. S�lo usando otro �ndice en computer:
Nestloop
-> Index Scan using comp_manufidx on computer
-> Index Scan using soft_hostidx on software |
dando como resultado de la query de las reglas
DELETE FROM software WHERE computer.manufacurer = 'bim'
AND software.hostname = computer.hostname; |
En cualquiera de estos casos, las queries extra del sistema de reglas ser�n
m�s o menos independientes del n�mero de filas afectadas en la query.
Otra situaci�n son los casos de UPDATE donde depende del cambio de un
atributo si la acci�n deber�a realizarse o no. En la versi�n 6.4 de
Postgres, la especificaci�n de atributos para
acontencimientos de reglas se ha deshabilitado (y tendr� su regreso en la
6.5, quiz� antes �permanezcan en antena!). De modo que por ahora la �nica
forma de crear una regla como en el ejemplo de shoelace_log es hacerlo con
una cualficaci�n de la regla. Eso da como resultado una query adicional que
se realiza siempre, incluso si el atributo que nos interesa no puede ser
cambiado de ninguna forma porque no aparece en la lista objetivo de la
query inicial. Cuando se habilite de nuevo, ser� una nueva ventaja del
sistema de reglas sobre los triggers. La optimizaci�n de un trigger deber�
fallar por definici�n en este caso, porque el hecjo de que su accoi�n solo
se har� cuando un atributo espec�fico sea actualizado, est� oculto a su
funcionalidad. La definici�n de un trigger s�lo permite especificar el
nivel de fila, de modo que si se toca una fila, el trigger ser� llamado a
hacer su trabajo. El sistema de reglas lo sabr� mir�ndo la lista objetivo y
suprimir� la query adicional por completo si el atributo no se ha tocado.
De modo que la regla, cualificada o no, s�lo har� sus barridos si tiene
algo que hacer.
Las reglas s�lo ser�n significativamente m�s lentas que los triggers si sus
acciones dan como resultado joins grandes y mal cualificadas, una situaci�n
en la que falla el optimizador. Tenemos un gran martillo. Utilizar un gran
martillo sin cuidado puede causar un gran da�o, pero dar el toque correcto,
puede hundir cualquier clavo hasta la cabeza.