Copy & Paste Engineer

MySQL の SYSDATE() と NOW() の違いを整理する

MySQL の SYSDATE() と NOW() の違いを整理する

MySQLで現在日時を取得する代表的な関数は SYSDATE()NOW() の2つです。一見同じ値を返しそうですが、評価タイミングやレプリケーションとの相性が異なります。本稿ではそれぞれの挙動と使い分けの指針をまとめます。

NOW() はステートメント開始時刻を返す

NOW()(およびエイリアスの CURRENT_TIMESTAMP)はステートメントの開始時刻をキャッシュし、同じステートメント内で複数回呼び出しても同じ値を返します。トランザクション中でも、各ステートメントの開始時刻が採用されるため、監査用の作成日時・更新日時に向いています。

SELECT NOW() AS first,
       SLEEP(2) AS wait,
       NOW() AS second; -- first と second は同じタイムスタンプ

トランザクション境界を跨いだ場合は、次のステートメントの開始時刻で再評価されるため、コミット時間と保存したタイムスタンプがずれにくいのが特徴です。

SYSDATE() は呼び出し時のリアルタイム値を返す

SYSDATE() は呼び出し時点でサーバーが知る現在時刻を都度取得します。既定値のままでは、同一ステートメント内でも再評価されるため、処理の遅延を含めた実時計測に向いています。

SELECT SYSDATE() AS first,
       SLEEP(2) AS wait,
       SYSDATE() AS second; -- second は first より約 2 秒進む

コマンドラインオプション(またはシステム変数)で sysdate_is_now = ON を指定すると SYSDATE()NOW() と同じくステートメント開始時刻を返すようになりますが、互換性確保のため既定では無効です。

主な違いの早見表

観点 NOW() SYSDATE()
評価タイミング ステートメント開始時に固定 呼び出しのたびに評価
レプリケーション ステートメントベースでも安全 ステートメントベースでは非決定的で警告対象
エイリアス・同義語 CURRENT_TIMESTAMP など なし(sysdate_is_now で挙動変更可)
主な用途 作成日時・更新日時のトラッキング 実際の処理時間測定、定期ジョブの時刻計測

バイナリログとレプリケーションでの扱い

ステートメントベースのバイナリログ(binlog_format = STATEMENT)では、SYSDATE() の非決定的な挙動が複製先で異なる結果を招く恐れがあります。MySQL 8.0 では SYSDATE() を含むステートメントをログに書く際に警告が出力され、行ベースまたは混合モードへの切り替えが推奨されます。NOW() はステートメント開始時に固定されるため、既定設定でもレプリケーションが安全に行えます。

どうしても SYSDATE() を使いたい場合は、以下のいずれかを検討します。

使い分けの指針

まとめ

参考文献