今天在代码的时候无意中看到
void Item_func_now_local::store_now_in_TIME(MYSQL_TIME *now_time) { THD *thd= current_thd; thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t)thd->query_start()); thd->time_zone_used= 1; } tem_func_sysdate_local::store_now_in_TIME(MYSQL_TIME *now_time) { THD *thd= current_thd; thd->variables.time_zone->gmt_sec_to_TIME(now_time, (my_time_t) my_time(0)); thd->time_zone_used= 1; }
可以看到now()函数取的是这个语句执行开始时的时间
inline time_t query_start() { query_start_used=1; return start_time; }
而sysdate取得是执行到这个函数点的时间。
time_t my_time(myf flags __attribute__((unused))) { ..... while ((t= time(0)) == (time_t) -1) ..... }
所以就有了这个现象(当然别设置–sysdate-is-now )
mysql> select sysdate(), sleep(3), sysdate(); +---------------------+----------+---------------------+ | sysdate() | sleep(3) | sysdate() | +---------------------+----------+---------------------+ | 2011-03-07 15:02:48 | 0 | 2011-03-07 15:02:51 | +---------------------+----------+---------------------+
基于statement replication,源端的now(), sysdate() 等函数都是原封不动的传递到对端。
对端应用binlog的时候,sysdate()自然就会使用本地的时间,所以用sysdate()除了检测slave lag,没有别的用处, 还容易误用。
那么now() 是如何保证与源节点的时间一样呢?
通过mysqlbinlog可看到大量的set timestamp 语句。
每个event group 的最开始都会使用set timestamp来决定这次查询的开始点,而这个设置影响到group内的now()。
我们来看看set timestamp 的函数实现,从sql/sql_yacc.yy 的关键字set:出发,跳到sql/sql_parse.cc
的sql_set_variables, 再来到sql/set_var.cc的实现类
bool sys_var_timestamp::update(THD *thd, set_var *var) { thd->set_time((time_t) var->save_result.ulonglong_value); return 0; }
转到set_time的实现sql/sql_class.h
class THD :public Statement, public Open_tables_state { ....... inline void set_time(time_t t) { start_time= user_time= t; ........
可以看到set timestamp 就是修改start_time, 而从上面的now()可以看到,now()取的就是start_time。
replication就是依靠存储在event里的set timestamp 来保证now函数的时间一致的。
ps: sysdate函数应该是源自于Oracle, dataguard是基于data block,进入block之前sysdate已经计算出写入,所以不存在这个问题。
觉得文章有用?立即:
和朋友一起 共学习 共进步!