环境:MYSQL5.1.42,WINDOWS XP,免安装版本在5.1参考手册里,有这么一段话对复制存储程序和函数的行为有什么限制?
嵌入到存储程序中的不确定(随机)或时基行不能适当地复制。随机产生的结果,
仅因其本性,是你可预测的和不能被确实克隆的。
因此,复制到从服务器的随机行为将不会镜像那些产生在主服务器上的。
注意, 声明存储程序或函数为DETERMINISTIC或者在log_bin_trust_routine_creators中设置系统变量为0 
将会允许随即值操作被调用。此外,时基行为不能在从服务器上重新产生,
因为在存储程序中通过对复制使用的二进制日志来计时这样的时基行为是不可重新产生的,
因为该二进制日志仅纪录DML事件且不包括计时约束。
 最后,在大型DML行为(如大批插入)中非交互表发生错误,该非交互表可能经历复制,
在复制版的非交互表中主服务器可以被部分地从DML行为更新。但是因为发生的那个错误,
对从服务器没有更新。 对函数的DML行为,工作区将被用IGNORE关键词来执行,
以便于在主服务器上导致错误的更新被忽略,并且不会导致错误的更新被复制到服务器。红色字体部分,说明在处理时基行为的时候,不写日志文件,并不能复制到从服务器上。比如在主服务器上有insert into t select now();这样的操作,写入的是主服务器的当前时间,如果取到从服务器上后,NOW()的时间很可能是不一样的,这样的话主从的数据就会不一致。所以对于这样的不确定性的数据,在主从的时候不记录到日志文件,然后也不在从服务器执行,看起来是正确的策略。测试一下看看。在主服务器的一个表里写入一条NOW()的数据,然后看看日志文件是否有记录
D:\mysql6\bin>mysqlbinlog d:\mysql6\data\mysql.000010use cpc/*!*/;
SET TIMESTAMP=1275750140/*!*/;
SET @@session.pseudo_thread_id=5/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=0/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp1`()
begin
insert into t1 values(100,100);
end
/*!*/;
# at 261
#100605 23:02:28 server id 1  end_log_pos 328   Query   thread_id=5     exec_time=0     error_code=0
SET TIMESTAMP=1275750148/*!*/;
BEGIN
/*!*/;
# at 328
#100605 23:02:28 server id 1  end_log_pos 420   Query   thread_id=5     exec_time=0     error_code=0
SET TIMESTAMP=1275750148/*!*/;
insert into t1 values(100,100)
/*!*/;
# at 420
#100605 23:02:28 server id 1  end_log_pos 447   Xid = 215
COMMIT/*!*/;
# at 447
#100605 23:35:51 server id 1  end_log_pos 539   Query   thread_id=6     exec_time=0     error_code=0
SET TIMESTAMP=1275752151/*!*/;
create table t2(a varchar(50))
/*!*/;
# at 539
#100605 23:36:27 server id 1  end_log_pos 606   Query   thread_id=6     exec_time=1     error_code=0
SET TIMESTAMP=1275752187/*!*/;
BEGIN
/*!*/;
# at 606
# at 648
#100605 23:36:27 server id 1  end_log_pos 648   Table_map: `cpc`.`t2` mapped to number 63
#100605 23:36:27 server id 1  end_log_pos 715   Write_rows: table id 63 flags: STMT_END_FBINLOG '
+24KTBMBAAAAKgAAAIgCAAAAAD8AAAAAAAAAA2NwYwACdDIAAQ8ClgAB
+24KTBcBAAAAQwAAAMsCAAAQAD8AAAAAAAEAAf/+JDM2ZjBmNTE0LTcwYjgtMTFkZi04YTcxLWRl
NjM1Njg3OWY4OA==
'/*!*/;# at 715
#100605 23:36:27 server id 1  end_log_pos 742   Xid = 227
COMMIT/*!*/;
# at 742
#100605 23:37:35 server id 1  end_log_pos 809   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1275752255/*!*/;
BEGIN
/*!*/;
# at 809
#100605 23:37:35 server id 1  end_log_pos 900   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1275752255/*!*/;
INSERT INTO t2 VALUES('3,80')
/*!*/;
# at 900
#100605 23:37:35 server id 1  end_log_pos 927   Xid = 235
COMMIT/*!*/;
# at 927
#100605 23:49:45 server id 1  end_log_pos 1002  Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1275752985/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
BEGIN
/*!*/;# at 1002
#100605 23:49:45 server id 1  end_log_pos 1100  Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1275752985/*!*/;
INSERT INTO t2 VALUES(NOW())
/*!*/;
# at 1100
#100605 23:49:45 server id 1  end_log_pos 1127  Xid = 236
COMMIT/*!*/;
# at 1127
#100606  2:15:14 server id 1  end_log_pos 1146  Stop
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;D:\mysql6\bin>
打开日志文件,却发现测试的写入NOW()的语句赫然在内,如红色加粗所示。
从库的IO进程读到后,在从机器上执行,这时主从数据就不一致了。有点没想明白。
mysql> select * from t2;
+--------------------------------------+
| a                                    |
+--------------------------------------+
| 36f0f514-70b8-11df-8a71-de6356879f88 |
| 3,80                                 |
| 2010-06-05 23:49:45                  |
+--------------------------------------+
3 rows in set (0.05 sec)在表里插入uuid(),这个随机数据,在日志文件里面是没有记录的。
insert into t2 select uuid();
这样在主库有这条记录了,从库又没有。符合手册的说明。
现在对NOW()这个问题,还迷糊。半夜3点起来求助,希望能搞清楚这个问题。

解决方案 »

  1.   

    看来从服务器是基于LOG来redo那些数据的。NOW()如果被直接的用于从服务器上,肯定得到不一致的数据。
    也许MySQL可以做到一致,那就是实时算出NOW()的值,计入LOG。
      

  2.   

    我想明白了。。对于这个NOW,或者不管是NOW还是其他的,在每个DDL,DML语句写入到二进制文件的时候,就记录了当前写入的时间,也就是服务器的时间。在二进制里有这些不要忽略了SET TIMESTAMP=1275752255/*!*/;
    INSERT INTO t2 VALUES('3,80')SET TIMESTAMP=1275752985/*!*/;
    INSERT INTO t2 VALUES(NOW())再测试一下,
    mysql> select now();
    +---------------------+
    | now()               |
    +---------------------+
    | 2010-06-06 11:33:13 |
    +---------------------+
    1 row in set (0.00 sec)mysql> SET TIMESTAMP=1275752985;
    Query OK, 0 rows affected (0.00 sec)mysql> select now();
    +---------------------+
    | now()               |
    +---------------------+
    | 2010-06-05 23:49:45 |
    +---------------------+
    1 row in set (0.00 sec)mysql>
    完全是这样的,它留下了蛛丝马迹。
      

  3.   

    mysql> SET TIMESTAMP=1275752985;
    Query OK, 0 rows affected (0.00 sec)设置完后,时间跑到昨天晚上11点多了,不知道怎么改回来。
    卖糕的,这下完了。重新启动MYSQL服务,恢复正常了。
    如果不重启服务,有什么办法恢复吗??另外这个1275752985是怎么计算出来的??
      

  4.   

    是这么算出来的:
    mysql> select adddate('2010-06-05 23:49:45', interval -1275752985 second);
    +-------------------------------------------------------------+
    | adddate('2010-06-05 23:49:45', interval -1275752985 second) |
    +-------------------------------------------------------------+
    | 1970-01-01 08:00:00                                         |
    +-------------------------------------------------------------+
    1 row in set (0.00 sec)想恢复是吧。
    假设当前时间是:
    '2010-06-06 18:21:30'
    可以先算出timestamp值:
    mysql> select timestampdiff(second, timestamp('2010-06-06 18:21:30'), timestamp('1970-01-01 08:00:00'));
    +-------------------------------------------------------------------------------------------+
    | timestampdiff(second, timestamp('2010-06-06 18:21:30'), timestamp('1970-01-01 08:00:00')) |
    +-------------------------------------------------------------------------------------------+
    |                                                                               -1275819690 |
    +-------------------------------------------------------------------------------------------+
    1 row in set (0.02 sec)
    mysql> select now();
    +---------------------+
    | now()               |
    +---------------------+
    | 2010-06-06 18:29:23 |
    +---------------------+
    1 row in set (0.00 sec)mysql> set timestamp=1275819690;
    Query OK, 0 rows affected (0.00 sec)mysql> select now();
    +---------------------+
    | now()               |
    +---------------------+
    | 2010-06-06 18:21:30 |
    +---------------------+
    1 row in set (0.00 sec)
      

  5.   

    指定那个timestamp只对当前会话有效。