MySQL replication: temporarily prevent specific SQL statements replicating to the slaves? - mysql

I want to connect and execute one (or sometimes several) SQL statements, and NOT have those replicated to the slaves.
I have no replicate-do or replicate-ignore configs, so I can't use some non-replicated database to send the commands from. And I know about:
set global sql_slave_skip_counter = 1
But that's on the slave. I'd like to be able to run a similar command on the master and have the following N commands not sent out to the slaves (which I guess means not logged in the binlogs, either).

SET sql_log_bin=0 is what you're looking for. Requires SUPER priv., and will turn off logging of commands from your session until you set it back to 1. See http://dev.mysql.com/doc/refman/5.0/en/server-session-variables.html#sysvar_sql_log_bin
SET sql_log_bin=0;
UPDATE ... ;
INSERT ... ;
DELETE ... ;
SET sql_log_bin=1 ;

BE CAREFUL.....!
SET sql_log_bin=0;
Master MySQL server automatically set this 0 value to 1 after a while(after about one minute). It does not wait until we explicitly set it to 1. So according to my experience this not a safe way to turn off binary logging at all.....!

Related

Force drop a database [no ifs ands or buts]

I have a staging server in which I need to drop a database and re-populate it with different tables. This is normally as easy as:
DROP DATABASE testbd;
However, usually whenever I drop the staging database, there are about 100 (valid) connections to it, and I do not care about those. Is there a fool-proof method to do a drop database without having to figure out whether there are open transactions, or this or that?
My thought was doing something like the following conceptually:
# get a global lock on everything -- no one except me can do anything now
CREATE LOCK
# get all active connections and then kill them
select concat('CALL mysql.rds_kill( ',id,');') from information_schema.processlist where DB='avails';
-- run each select statement
# drop the database
DROP DATABASE testdb
# if this is required?
END LOCK
The above is pseudo-code but I'm basically looking for a way to be able to issue a command and the database to drop within 5 seconds in a failproof way.

Identify that a trigger in the slave has been invoked by a replicated statement

How can I detect into a trigger in my slave that it has been invoked by a replicated statement in MySQL?
I've tried with USER() function, but it returns null when the trigger is activated by a replicated statement. Shouldn't it returns replication user (repl)?
Example:
CREATE TRIGGER `test`.`t1_BEFORE_INSERT` BEFORE INSERT ON `t1` FOR EACH ROW
BEGIN
IF USER() LIKE 'repl#%'
THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Custom error';
END IF;
END
I want the behaviour of the trigger to be different depending of it's activated by a replicated statement or not. I've configured statement based replication and I've tested that triggers run in my slave.
Try checking ##server_id. This is a global variable that must be unique for each MySQL instance in the replica-set.
Another option might be to change the trigger code on the replica. I don't usually like to do this, because I'd prefer that all schema objects are identical between the master and replica.
PS: You already know this, but for the benefit of other readers: note that replicated events do not execute triggers if you use row-based replication. This means you get mixed results if you used mixed-mode replication, because events will be logged in row-based format if the SQL is not safe for replication.
Re your comment:
Regarding testing the user, there is no user session in the replication thread. The replication thread is effectively runs without any limits with respect to the SQL privilege system (it can execute any change in the binary log stream), so there's no need for that thread to be associated with a user.
So it's not surprising that USER() returns NULL.
You could try testing for that:
IF USER() IS NULL THEN ...
By the way, there's actually no information in your question above that says that the trigger exists only on the replica.

Is it possible to stop mysql errors for non-replicated databases breaking replication?

I was a bit surprised to see a mysql slave show that replication had stopped due to a replication error. The error it showed was one from the master, but on a database that isn't replicated.
One the master there is the current config in /etc/my.cnf in the [mysqld] section:
binlog-do-db=some_db_1
binlog-do-db=some_db_2
binlog-do-db=some_db_3
On the slave these databases are replicated without issue. The replicated type we're using is MIXED. The error on the slave which stopped replication, however, was a statement relating to another database:
Last_SQL_Error: Error 'Table 'some_db_4.some_table' doesn't exist' on query.
I presume that this is because it was referenced with the schema.table syntax and not with a use statement, but is there a way of stopping this from happening? Am I right in saying that normally, if I ran the following:
USE some_db_2;
UPDATE some_table SET some_column = 1 WHERE some_column = 0;
USE some_db_4;
UPDATE some_table SET some_column = 2 WHERE some_column = 1;
Then only the first two lines would appear in the binlog? Whereas with:
UPDATE some_db_2.some_table SET some_column = 1 WHERE some_column = 0;
UPDATE some_db_2.some_table SET some_column = 2 WHERE some_column = 1;
both would appear in the binlog? Is it possible to stop this?
Replication filtering works by filtering on whatever is the default database when you run the query -- not the database affected by the query.
So you can get into trouble if you use qualified table names, changing data in some_db_4 while your current default database is not that database.
Similar problems exist if you do cross-database DML, like an INSERT into a table in some_db_3 from a SELECT from a table in some_db_4, which doesn't exist on the slave.
So the answer to your question is yes, you can avoid this error if you are careful to execute DML on the master only when your default database is the database affected by the statement.

MySQL Row-Based Replication (RBR) - Log file containing unexpected statement

I just configure 2 mySQL servers for a MASTER-MASTER replication.
I choose the RBR replication for some reason.
My congifuration on the server ONE :
#replication
server-id=1
binlog_do_db = db1
binlog_ignore_db = db2
log-bin="C:/ProgramData/MySQL/my56"
auto_increment_increment = 2
auto_increment_offset = 1
binlog_format=ROW
replicate_do_db=db1
and on the server TWO :
#replication
server-id=2
binlog_do_db = db1
log-bin="C:/ProgramData/MySQL/my56"
auto_increment_increment = 2
auto_increment_offset = 2
binlog_format=ROW
replicate_do_db=db1
With this, the replication works.
For example, on server ONE, if I execute :
USE db1;
INSERT INTO db1.table1 values (foo,bar);
It's works on the server TWO.
If on server ONE I execute :
USE db1;
INSERT INTO second_db.table2 values (foo,bar);
The insert is not execute on the server TWO, it's good.
If on server ONE I execute :
CREATE table db1.tableFoo(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
The create table is not execute on the server TWO, it's good because I choose the Row-Based replication, so I have to manualy execute the CREATE STATEMENT on server TWO. It's what I want.
Now, there is my problem :
If on the server ONE I execute :
USE db1;
CREATE table db1.tableFoo(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
The CREATE TABLE is execute on the server TWO, it's NOT good ! Normally with the Row-Based Replication the CREATE ORDER is not replicated.
Worst, if after the USE db1; if create a table in another database, the CREATE TABLE is replicated on my server TWO, and my slave is aborted on the server TWO because de database doesn't exist...
Do you have any idea ? I dont want any CREATE / ALTER / CREATE USER ... send to my replication even if I use à USE db1;
I based my work on the mySQL documentation, especially this one : http://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html
Thank you and merry Xmas !
DDL statements are always logged using statement-based replication, regardless of whether you've chosen RBR or not. As a result, the default (current) database is important when you execute CREATE TABLE statements.
From http://dev.mysql.com/doc/refman/5.6/en/replication-options-binary-log.html#option_mysqld_binlog-do-db :
DDL statements such as CREATE TABLE and ALTER TABLE are always logged as statements, without regard to the logging format in effect, so the following statement-based rules for --binlog-do-db always apply in determining whether or not the statement is logged.
...Only those statements are written to the binary log where the default database (that is, the one selected by USE) is db_name.
This suggests that the behavior you observe is expected, although it is a bit odd.
If possible, I'd suggest that you USE an unreplicated DB (for example mysql) before executing DDL that you do not want to replicate in your application.

How to find out all the commands executed on a MySQL database within a given timeframe?

Is it possible to find out all the command executed against a database in a given timeframe? For example, I would like to know who executed insert command on a database table in the last 24 hours.
Any help would be greatly appreciated.
Thanks.
For queries which change data, you can check the binary log. However, I don't think this'll get you the user:
$ mysqlbinlog /var/log/mysql/mysql-bin.000145
…
# at 3178
#090805 6:25:15 server id 1 end_log_pos 3373 Query thread_id=2170317 exec_time=0 error_code=0
SET TIMESTAMP=1249467915/*!*/;
UPDATE phpbb3_topics
SET topic_views = topic_views + 1, topic_last_view_time = 1249467915
WHERE topic_id = 95847/*!*/;
# at 3373
…
To get the user, you'll need to set up triggers on the tables and use those triggers to store an audit log in another table.
If you need to all queries—selects included—there is also the general query log but that is not normally on due to performance impacts and disk requirements.
http://dev.mysql.com/doc/refman/5.0/en/binary-log.html
Binary log might help a bit.