Ok,I'm running a setup with a single master and a number of slaves. All writes go through the master and are replicated down to the slaves which are used strictly for reads.
Now I have a stored procedure (not function) which is called by a trigger on an insert. According to the MySQL docs, for replication triggers log the call to the trigger while stored procedures actually log the result of the stored procedure.
So my question is, when my trigger gets fired, will it replicate both the trigger and the results of the procedure that the trigger calls (resulting in the procedure effectively being run twice)? Or will it simply replicate the trigger have the slaves re-run the stored procedure on their own?
Thanks
In MySQL 5.0 (and MySQL 5.1 with statement based binary logging), only the calling query is logged, so in your case, the INSERT would be logged.
On the slave, the INSERT will be executed and then the trigger will be re-run on the slave. So the trigger needs to exist on the slave, and assuming it does, then it will be executed in exactly the same way as the master.
In MySQL 5.1, there is row-based binary logging, which will log only the rows being changed, so the trigger would not be re-fired on the slave, but all rows that changed would still be propagated.
In addition to Harrison's excellent answer:
Assuming the databases are in sync (schema, data, same version) to start with, it should just work
If it doesn't, then it may be that you're using something non deterministic in your queries or trigger. Fix that.
Regardless of how you use replication, you need to have monitoring to check that the slaves are always in sync. Without any monitoring, they will become out of sync (subtly) and you won't notice. MySQL has no automatic built-in feature for checking this or fixing it.
Related
I need to encrypt some data on MySQL slave and using AES_Encrypt for the same. Is it possible to encrypt it while replicating it from the Master database?
Using MySQL 5.6
In MySQL replication, when using binlog_format=STATEMENT, triggers fire on the master and again on the slave, but there is no specific requirement that the triggers be defined identically on the master and slave, or that triggers be provisioned on both.
I say there is no specific requirement, because it is not enforced. If you want the data to be identical on master and slave -- as is almost always the case in a replicated environment -- then yes, the triggers have to be defined identically on both servers... but it is possible to customise the slave triggers -- and one way of doing it would be to define BEFORE INSERT and BEFORE UPDATE triggers on the slave that encrypted the columns before inserts and updates.
This does require STATEMENT replication, which I don't use because it is more delicate and some statements cannot be deterministically replicated in STATEMENT mode.
This would require extra care to ensure that master and slave are always consistent, and would require custom tools since standard table comparison tools would consider master and slave tables to be different.
With binlog_format=ROW, any triggers defined on the slave are ignored for replicated events, because they would be redundant -- the changes done by the triggers on the master will already be replicated to the slave as row events, and executing the triggers on the slave would not have the correct result. Row-based replication uses raw row images, so is always deterministic, unlike statement based replication.
The MariaDB team recognizes that there may be cases where identical data sets are not the objective, such as where you might want to build denormalized query tables on the slave, so in MariaDB 10.1, they introduced a feature to allow slaves to fire triggers for row-based events. This might also be a viable solution, if your master is not using statement-based replication. It does not appear to require the master to run MariaDB, only the slave.
https://mariadb.com/kb/en/mariadb/running-triggers-on-the-slave-for-row-based-events/
It is also possible to create accounts that cannot access all columns, since the MySQL permissions model allows grants to be made at the server, database, table, and column level. Without permission to access a column, you won't see it, in spite of it being there.
Arguably, though, if the data is sensitive, the most correct solution would be to encrypt it on the master.
I have one master and 2 slaves and have replication set at statement level.
I want to purge records older than specific date on master and one of the slave. I created a procedure to do that.
Is there any way I can skip procedure call on 2nd slave and execute that on 1st slave?
Please note that I want to execute all other statements and I want to schedule purge procedure call as MySQL event.
Thanks and best regards,
Santosh!
Declare the procedure to some sort of No-Op on the 2nd slave. The statement will still get sent and processed but won't do anything.
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.
I have the following MySQL 5.5.16 setup, properly running:
Server A w/ db.a and db.b
Server B configured as slave for db.a (not db.b), by means of --replicate-wild-do-table
Tables on Srv.A-db.b have triggers on insert that insert/update db.a
db.a is properly replicated in Server.B, ie, if an update via an SQL client on db.a on server.A happens, is properly replicated to db.a on Server.B
Now comes the problem: triggers on Server.A/db.b that update/insert db.a are not replicated... have lost many hours exhausting all my knowledge on this...
On Srv.A/db.b I finally created a federated table pointing to Srv.A/db.a and the triggers working through the federated table are properly replicating but is VERY slow and some things cannot be used (ON DUPLICATE UPDATE for example)... so is really a stop-goat solution.
If I try to replicate both db.a and db.b the triggers work ok, but db.b is HUGE and not supposed to be replicated the server.B.
Any suggestions on how to make triggers work on db.b-->db.a when only db.a is replicated ??
Thanks for the suggestion.
See MySQL Trigger FAQ B.5.12: http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html#qandaitem-B-5-1-12
'Triggers and replication in MySQL 5.0 work in the same way as in most other database systems: Actions carried out through triggers on a master are not replicated to a slave server.'
Maybe you can change all events that cause the trigger to run to instead call a stored procedure which will do the same work the trigger does now.
I am running a couple of databases on MySQL 5.0.45 and am trying to get my legacy database to sync with a revised schema, so I can run both side by side. I am doing this by adding triggers to the new database but I am running into problems with replication. My set up is as follows.
Server "master"
Database "legacydb", replicates to server "slave".
Database "newdb", has triggers which update "legacydb" and no replication.
Server "slave"
Database "legacydb"
My updates to "newdb" run fine, and set off my triggers. They update "legacydb" on "master" server. However, the changes are not replicated down to the slaves. The MySQL docs say that for simplicity replication looks at the current database context (e.g. "SELECT DATABASE();" ) when deciding which queries to replicate rather than looking at the product of the query. My trigger is run from the context of database "newdb", so replication ignores the updates.
I have tried moving the update statement to a stored procedure in "legacydb". This works fine (i.e. data replicates to slave) when I connect to "master" and manually run "USE newdb; CALL legacydb.do_update('Foobar', 1, 2, 3, 4);". However, when this procedure is called from a trigger it does not replicate.
So far my thinking on how to fix this has been one of the following.
Force the trigger to set a new current database. This would be easiest, but I don't think this is possible. This is what I hoped to achieve with the stored procedure.
Replicate both databases, and have triggers in both master and slave. This would be possible, but a pain to set up.
Force the replication to pick up all changes to "legacydb", regardless of the current database context.
If replication runs at too high a level, it will never even see any updates run by my trigger, in which case no amount of hacking is going to achieve what I want.
Any help on how to achieve this would be greatly appreciated.
This may have something to do with it:
A stored function acquires table locks before executing, to avoid inconsistency in the binary log due to mismatch of the order in which statements execute and when they appear in the log. Statements that invoke a function are recorded rather than the statements executed within the function. Consequently, stored functions that update the same underlying tables do not execute in parallel.
In contrast, stored procedures do not acquire table-level locks. All statements executed within stored procedures are written to the binary log.
Additionally, there are a whole list of issues with Triggers:
http://dev.mysql.com/doc/refman/5.0/en/routine-restrictions.html