BEFORE or AFTER trigger for maintaining audit log - mysql

I've been reading the MySql 5.0 comment stream on the create trigger page
and I would like to ask the community if the recommendations are good & whether they still apply to 5.1. What I've noticed playing with triggers today is that it is impossible to update a field in the old table using a AFTER UPDATE.
Be careful with BEFORE triggers. Constraints may occur, specifically if you are using InnoDB engine, where an insert will fail, but actions from your BEFORE trigger will succeed.
Use BEFORE triggers primarily for constraints or rules, not transactions, tweaking the NEW.* columns should be fine.
Stick with AFTER triggers for most other operations, such as inserting into a history table or updating a denormalization.

Yes. AFAIK, MySQL 5.1 did not make any changes to the semantics of how triggers work. MySQL tries to support the ANSI/ISO SQL specification for trigger semantics.
You can imagine there's a sequence of operations that runs as a row is written to the database:
Run BEFORE triggers
Evaluate constraints, enforce NOT NULL, apply DEFAULT values
Write the row to the database
Update indexes
Run AFTER triggers
Once you've reached the AFTER trigger, it's too late to change values in the row. In some databases, you can set NEW.somecolumn = 1234 but this change is silently discarded as the AFTER trigger finishes. In other databases, it helps you understand your mistake by giving you an error either when you define the trigger or when you run the trigger.
AFTER triggers are best used for extra actions to take as a result of INSERT/UPDATE of the row, such as the audit logging you mentioned. For one thing, MySQL only permits one trigger per action per table, so if you are also using a BEFORE trigger to change values and enforce business rules, now you can at least keep the extra actions in a separate trigger. That makes it easier to update one or the other.
The other consideration is that you should probably do extra actions only after you know the row has been saved successfully. E.g. it wouldn't be right to log a change in a BEFORE trigger, and then have the change abort because of a NOT NULL constraint.
For DELETE actions where you need to remove dependent rows in other tables, you may still have to do that in a BEFORE trigger.

Related

Mysql trigger performance vs php manual insert

I want to create a notification after insertion on some tables. For example whenever a user inserts a comment I create a notification for the administrators that this user has created a comment.
I used to do it manually in the PHP, It wasn't as that bad, It was something like that:
// after the comment is created
Notification::create(....);
Not bad, but sometimes I give the user the ability to add images, posts, ..etc. So I have to remember every time to insert a notification.
So I am thinking of using a mysql trigger instead. But I am worry how that will affect the performance?
One last thing, Is it possible to create a trigger after insert on multiple tables?
Thanks,
Is it possible to create a trigger after insert on multiple tables?
No, it is not possible. You have to create a separate trigger for each table.
I am worry how that will affect the performance?
Performance wise it shouldn't be a disaster although by introducing triggers you artificially prolong insert/update operations on you tables (images, posts, ...) effectively increasing locking time.
But performance is not the only factor to consider. Maintainability should be important too. By creating triggers you scatter you application logic between your app and database. It's harder to test. Triggers are often forgotten e.g. when you transfer the schema or produce a dump. Sometimes you don't want them to fire while you do some maintenance DML on your tables. But MySQL lacks this capability. You'll have to use workarounds for that.
Bottom line: consider not to use triggers unless you have to.

How are database triggers implemented inside a SQL database engine?

How are triggers implemented inside a SQL database engine? I am not referring to the SQL language-level trigger definitions but rather their underlying implementations inside Oracle, SQL Server, MySQL, etc. How can the database engine scalably manage hundreds or thousands of triggers? Do they use a publish-subscribe model like with an observer/listener pattern? Any pointers to relevant literature on the subject would also be appreciated.
I did google for "database trigger implementation" but all I found was information on SQL trigger definitions, which again is not want I'm looking for.
Triggers are callbacks, so the implementation can be as simple as function pointers in C. Normally, a user is not expected writing user-defined procedural code in the RDBMS in C, though. You would need to support some other "higher-level" language. So the relevant programming pattern is DSL. The number of triggers (scalability) itself is not a problem because there is usually only one, max two per table and DML event triggers only these. The implementation challenge is elsewhere: in the areas of consistency, concurrency semantics.
You can explore source codes of open source databases.
For example PostreSql's trigger.
First off, triggers are pieces of code that are run when a particular event (e.g. INSERT/UPDATE/DELETE on a particular table) occurs in the database. Triggers are executed implicitly BEFORE or AFER the DML statement and triggers cannot be executed explicitly like stored procedures.
There are also two types of triggers - STATEMENT LEVEL triggers and ROW LEVEL triggers.
The STATEMENT LEVEL triggers are fired BEFORE or AFTER a statement is executed.
The ROW LEVEL triggers are fired BEFORE or AFTER an operation is performed on each individual row affected by the operation.
So we have 12 types of triggers:
1. BEFORE INSERT STATEMENT
2. BEFORE INSERT ROW
3. AFTER INSERT STATEMENT
4. AFTER INSERT ROW
5. BEFORE UPDATE STATEMENT
6. BEFORE UPDATE ROW
7. AFTER UPDATE STATEMENT
8. AFTER UPDATE ROW
9. BEFORE DELETE STATEMENT
10. BEFORE DELETE ROW
11. AFTER DELETE STATEMENT
12. AFTER DELETE ROW
Multiple triggers can be coded for an event with their order of precedence of execution mentioned.
Whenever we run a DML query (INSERT/UPDATE/DELETE) on a database, that query is run in a transaction. Hence when a query runs -
The table is locked
The DBMS checks for triggers that run BEFORE the statement is to be executed
Execute the actual SQL statement row-by-row.
The BEFORE trigger for EACH ROW is looked for. If found, executed.
Check for errors. If any, rollback the changes made by the statement or its triggers.
Any AFTER EACH ROW triggers are found and executed.
Any AFTER STATEMENT triggers are found and executed.
Different DBMS manage transactions differently. Refer to their documentation for details.
Many DBMS keep the triggers in text format only, not like stored procedures that are compiled.
It is best practice to call stored procedures from inside a trigger body as stored procedures are much faster performers than triggers.

MySQL history or transaction log table updated by triggers

my question is about a database history or transaction log table which is currently updated by mysql procedure. The procedure is called by mysql trigger every time when we keep a history of an appropriate table in during insert, update or delete actions. As far as we have lots of tables for each of them we need to create a separate trigger e.g. for "accounts table" we need to create "accounts_insert, accounts_update and accounts_delete" triggers.
The problem is every time when we alter "accounts table" we have to modify appropriate triggers as well.
Is there any way to avoid that manual work? Would it be better to implement it in application layer/code?
There are no 'global' triggers if that's what you're thinking about.
Application side logging is one possible solution. You'll want to do this within transactions whenever possible.
Other possible approaches:
Create a script that will update your triggers for you. Can be fairly easy, if your triggers are generally similar to each other. Using information_schema database can be helpful here.
Parse general query log (careful, enabling this log can have large negative impact on server's performance)

What to consider if using triggers on tables in a sql-server merge replication

i am driving since some years a sql-server2000 merge-replication over three locations. Triggers do a lot of work in this database. i got no troubles.
Now migrating these database to a brand new sql2008, i got some issues about the triggers. They are firing even if the merge-agent does his work.
Is there anybody who has some experience with that kind of stuff on sql2008-server?
Can anybody confirm that different behaviour to sql2000?
Peace
Ice
give this a read: Controlling Constraints, Identities, and Triggers with NOT FOR REPLICATION
In most cases the default settings are
appropriate, but they can be changed
if an application requires different
behavior. The main area to consider is
triggers. For example, if you define
an insert trigger with the NOT FOR
REPLICATION option set, all user
inserts fire the trigger, but inserts
from replication agents do not.
Consider a trigger that inserts data
into a tracking table: when the user
inserts the row originally, it is
appropriate for the trigger to fire
and enter a row into the tracking
table, but the trigger should not fire
when that data is replicated to the
Subscriber, because it would result in
an unnecessary row being inserted in
the tracking table.

Add every update, delete, insert query to a new record in MySQL

Is there a way that if there's a change in records, that a query that changed the data (update, delete, insert) can be added to a "history" table transparently?
For example, if mySQL detects a change in a record or set of records, is there a way for mySQL to add that query statement into a separate table so that way, we can track the changes? That would make "rollback" possible since every query (other than SELECT) would be able to reconstruct database from its first row. Right?
I use PHP to interact with mySQL.
You need to enable the MySQL BinLog. This automatically logs all the alteration statements to a binary log which can be replied as needed.
The alternative is to use an auditing function through Triggers
Read about transaction logging in MySQL. This is built in to MySQL.
MySQL has logging functionality that can be used to log all queries. I usually leave this turned off since these logs can grow very rapidly, but it is useful to turn on when debugging.
If you are looking to track changes to records so that you can "roll back" a sequence of queries if some error condition presents itself, then you may want to look into MySQL's native support of transactions.