ちょっと硬派なコンピュータフリークのBlogです。

カスタム検索

2009-04-27

SYSDATE()とNOW()の違い。

MySQLには、現在時刻を求める関数としてSYSDATE()とNOW()という2つの関数が実装されている。そして、それらは微妙に動作が違う。SYSDATE()は関数が呼び出された瞬間の時刻を返すのに対して、NOW()はクエリ開始時の時刻を返す。例えば、100秒かかるような長いクエリにおいて両者を利用した場合、SYSDATE()では結果に最大100秒の差が生じるのに対して、NOW()では差が生じない。NOW()では関数が最初に実行された時に結果がキャッシュされ、以降はキャッシュされた値が利用されるからだ。

次のようにSLEEP()を利用するとわかり易いだろう。
mysql> SELECT SYSDATE(), SLEEP(100), SYSDATE();
+---------------------+------------+---------------------+
| SYSDATE()           | SLEEP(100) | SYSDATE()           |
+---------------------+------------+---------------------+
| 2009-04-27 07:17:09 |          0 | 2009-04-27 07:18:49 | 
+---------------------+------------+---------------------+
1 row in set (1 min 40.00 sec)

mysql> SELECT NOW(), SLEEP(100), NOW();
+---------------------+------------+---------------------+
| NOW()               | SLEEP(100) | NOW()               |
+---------------------+------------+---------------------+
| 2009-04-27 07:19:56 |          0 | 2009-04-27 07:19:56 | 
+---------------------+------------+---------------------+
1 row in set (1 min 40.00 sec)

SYSDATE()では2つの結果が100秒異なっているのに対して、NOW()では同じ結果になっている。もしクエリにおいて一貫した値を取得したければ、SYSDATE()ではなくNOW()を使うといいだろう。

ちなみに、SYSDATE()とNOW()ではNOW()の方が高速である。なぜなら、結果をキャッシュするので実際に日付を求めるのは一度で済むからだ。とはいえ、SYSDATE()も十分高速なので実行回数がそれほど多くなければ問題にはならないのでそれほど気にする必要はない。例えば、実行回数が一億回などのように非常に多い場合には、次のように差が出てくる。
mysql> SELECT BENCHMARK(100000000,SYSDATE());
+--------------------------------+
| BENCHMARK(100000000,SYSDATE()) |
+--------------------------------+
|                              0 | 
+--------------------------------+
1 row in set (3 min 29.46 sec)

mysql> SELECT BENCHMARK(100000000,NOW());
+----------------------------+
| BENCHMARK(100000000,NOW()) |
+----------------------------+
|                          0 | 
+----------------------------+
1 row in set (1.93 sec)

SYSDATE()はOracle互換のために実装されている関数だ。もし、上記のような厳密な違いが必要ないのであれば、--sysdate-is-nowオプションをつけてMySQLサーバーを起動するといい。そうすると、SYSDATE()を実行した場合にもNOW()と同じ振る舞いをし、実行速度もNOW()と同じように速くなる。
mysql> SELECT BENCHMARK(100000000,SYSDATE());
+--------------------------------+
| BENCHMARK(100000000,SYSDATE()) |
+--------------------------------+
|                              0 | 
+--------------------------------+
1 row in set (1.91 sec)

僅かな差ではあるがNOW()の方が消費するリソースが少ないのは確かである。小さいところからコツコツと積み重ねていくのがエコの基本。MySQL DBAもエコでありたい。

1 コメント:

hironobu さんのコメント...

systedate()はver5.0で仕様が変わったんで、ver4.1以下ではsysdate()= now()だったような気が。もう覚えてないけど。

コメントを投稿