1. 程式人生 > >MYSQL的NOW和SYSDATE函數的區別

MYSQL的NOW和SYSDATE函數的區別

觸發 情況 sla striped lee strip 有意思 query 主庫

在MySQL Performance Blog博客上看到一篇文章介紹now()和sysdate()函數。

想起很多朋友專門問在MySQL裏面提供now()和sysdate()函數,都是表示取得當前時間,他們之間有什麽區別。我們下面來詳細看一下

首先大家可以看一下下面的一個詭異現象:

1 2 3 4 5 6 7 mysql> SELECT NOW(),SYSDATE(); +---------------------+---------------------+ | NOW() | SYSDATE() | +-----------------------------+----------------------------+
| 1999-01-01 00:00:00 | 2012-12-05 09:50:03 | +---------------------------+----------------------------+ 1 row in set (0.00 sec)

很有意思吧?
sysdate()得到的時間是當前時間,而now()取出來的時間竟然是“1999-01-01 00:00:00”。
首先申明,我不是PS或者修改得來的,你看完本文,我會教你在你的MySQL上也得出這樣的結果。

另外我們看一下,now()和sysdate()的另外一個區別:

1 2 3 4 5 6 7 8 9 10 11 12 13 mysql> SELECT NOW(), SLEEP(2), NOW();
+---------------------+----------+---------------------+ | NOW() | SLEEP(2) | NOW( | +-----------------------------+--------------+-----------------------------+ | 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 | +---------------------------+--------------+----------------------------+ mysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();
+---------------------+----------+---------------------+ | SYSDATE() | SLEEP(2) | SYSDATE() | +-----------------------------+--------------+----------------------------+ | 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 | +---------------------------+--------------+----------------------------+

在使用now()的情況下,雖然我們sleep了2秒,但是大家可以看到兩次now()函數輸出的結果都是’2006-04-12 13:47:36′
而使用sysdate()的情況下,是兩個時間’2006-04-12 13:47:44′,’2006-04-12 13:47:46’,正好相差兩秒。

這個最終的原因,大家可以直接查看MySQL的reference對now()函數的解釋:http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_now
我簡單給大家翻譯一下。
now()函數,返回的是當前的時間。但是當前的時間是怎麽取的列?

首先,對於now()函數來說,它取的時間是語句開始執行的那個時間,並且在語句執行過程中,這個值都不會變。甚至於,你在執行一個存儲過程或者觸發器時,這個值都是一直不變的。

這也就解釋了,為什麽sleep了2秒以後,在SELECT NOW(), SLEEP(2), NOW();語句中,取出的時間值是同一個:’2006-04-12 13:47:36’。

然後:now()函數取的當前時間從哪裏來?它取自mysql的一個變量”TIMESTAMP”。

很奇怪吧?

其實這個是由於MySQL的replication導致的。你可以想象一下,一個insert into gguard values (3,now());語句在兩臺MySQL上插入的值是不是一樣?now()如果像sysdate()一樣取的是機器的系統時間,那麽在MySQL的主庫和備庫執行同一個這樣的SQL語句,主庫和備庫的這一條數據肯定就不一致了。

主備庫不一致的問題必須要解決,兩種解決方式:

1、修復這種問題。

2、不使用statement的語句級別復制,而是類似於oracle的,將數據變更記錄下來,原樣在備庫執行一遍。

第二種方式就是大家熟知的,binlog_format=ROW的方式。第一種就是now()不使用機器系統時間,而是取mysql的變量”TIMESTAMP”值。

另外的類似的變量還包括insert_id(用於復制時,AUTO_INCREMENT的取值)等

利用mysqlbinlog你可以看到每個binlog event都有一個時間值。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 # at 441 #121205 10:06:52 server id 5 end_log_pos 526 Query thread_id=5 exec_time=0 error_code=0 SET TIMESTAMP=1354673212.982122/*!*/; BEGIN /*!*/; # at 526 #121205 10:06:52 server id 5 end_log_pos 642 Query thread_id=5 exec_time=0 error_code=0 use `test`/*!*/; SET TIMESTAMP=1354673212.982122/*!*/; insert into gguard values (3,now()) /*!*/; # at 642 #121205 10:06:52 server id 5 end_log_pos 669 Xid = 26 COMMIT/*!*/;

備庫復制執行時,SQL thread在做每個insert或者其他操作前首先要執行SET TIMESTAMP這樣的動作,保證now()函數在statement模式下在備庫和主庫一樣。
這裏還有另外一種含義:sysdate()函數在statement模式下,主庫和備庫會不一致,也就是說sysdate在statement復制模式下是不安全的。

那麽怎麽實現上面的SELECT NOW(),SYSDATE();查詢出來的時間不一樣列,你只需要在之前執行:

1 2 SET TIMESTAMP=UNIX_TIMESTAMP(‘1999-01-01‘); SELECT NOW(),SYSDATE();


體驗now()和sysdate()的神秘吧

註意:

CURRENT_TIMESTAMP() LOCALTIME() LOCALTIMESTAMP()都是now()函數的同義詞,不討論。
sysdate()沒有同義詞。
如果你覺得now()函數就夠了,你不需要每次都取當前的機器系統時間,那麽你可以在MySQL啟動時指定–sysdate-is-now,這樣的話MySQL會把sysdate()當成now()的一個同義詞。

MYSQL的NOW和SYSDATE函數的區別