読者です 読者をやめる 読者になる 読者になる

破棄されたブログ

このブログは破棄されました。

MySQL の now() 関数について

Web アプリにおいて、更新系クエリを MySQL に投げる時、now() 関数は使わんほうがいいんじゃねって思った。

想定する環境

状況

ユーザが投稿をポストすると、それをデータベースに記録するようなものを考える。
クエリを投げるテーブルの構造はこんな感じを想定。

  • テーブル名は post
  • id は auto_increment で、投稿がポストされる度一意に振られる。
  • uid は投稿したユーザの ID
  • body は投稿本文
  • posted_time は投稿日時
DESC post;
+-------------+----------+-----+----------------+
| Field       | Type     | Key | Extra          |
+-------------+----------+-----+----------------+
| id          | int(11)  | PRI | auto_increment |
| uid         | int(11)  |     |                |
| body        | text     |     |                |
| posted_time | datetime |     |                |
+-------------+----------+-----+----------------+

ここで、投稿を記録する際のクエリで now() を使うのは良くないなと思った。

INSERT INTO post (uid, body, posted_time) VALUES (1, "お寿司食べたい", now());
<?php
$uid  = 1;
$body = 'お寿司食べたい';

$sth = $dbh->prepare('INSERT INTO post (uid, body, posted_time) VALUES (?, ?, now())');
$sth->execute(array($uid, $body));
?>

理由

  • posted_time の値を固定できないので、扱いが面倒くさい。
  • Web サーバと DB サーバで時刻がずれている場合、レコードとアクセスログを対照させて調査を行うとかがシンドイ
  • 同一リクエスト内での更新にも関わらず、別々のタイムスタンプが記録される可能性がある。
  • タイムゾーンの設定によってはレプリケーションセーフでなくなる

対応策

普通に突っ込んでやる

<?php
$uid  = 1;
$body = 'お寿司食べたい';
$time = '2038-01-19 03:14:07'

$sth = $dbh->prepare('INSERT INTO post (uid, body, posted_time) VALUES (?, ?, ?)');
$sth->execute(array($uid, $body, $time));
?>

MySQL の now() 関数は「一応」レプリケーションセーフ

なぜか日本語版のリファレンスに書いてないんだけど、now() はレプリケーションセーフ。最初これも now() を使わない理由に入れてたんだけど、調べてみたら問題なかった。

For NOW(), the binary log includes the timestamp. This means that the value as returned by the call to this function on the master is replicated to the slave.

MySQL :: MySQL 5.1 Reference Manual :: 16.4.1.13 Replication and System Functions

ただし、条件があって、マスターとスレーブで同一タイムゾーンが設定されてないとダメ。

The correct solution is recorded some where else, that is, the same system time zone should be set for both master and slave.

Database Administration: NOW() function is not replication-safe

The same system time zone should be set for both master and slave. Otherwise, statements depending on the local time on the master are not replicated properly, such as statements that use the NOW() or FROM_UNIXTIME() functions.

MySQL :: MySQL 5.6 Reference Manual :: 16.4.1.28 Replication and Time Zones

うーん。まあ、マスターとスレーブとが別々のタイムゾーンにあるような環境には縁がないけど、やっぱり now() を使わないで、固定値を使った方がいろいろ心配しなくていいんじゃないかなあ。。。
最近は、自然災害対策でサーバを地理的に離れた DC に置くみたいな話もあるし、そーいうときはやっぱり怖いなー。

広告を非表示にする