MySQLを選んだときの注意点覚え書き

MySQLは個人的に馴染み深いDBであり、また広く使われているDBなのだが、結構引っ掛かる点があったりする。雑感程度にまとめておきたい。

2012/09/24追記 MySQL 5.6での日付型マイクロ秒対応

JDBCドライバのPreparedStatementがデフォルトでは静的プレースホルダではない

IPA安全なSQLの呼び出し方」の「5.5 Java+MySQL」によると、

デフォルトでは動的プレースホルダが選択されるので、静的プレースホルダを使用するには、DB 接続時に useServerPrepStmts=true というパラメータを指定する必要があります。

とあり、初期状態では動的プレースホルダを使ってSQLを組み立ててからMySQLサーバーに送信している。つまり、JDBCドライバの実装に問題があれば、SQLインジェクションが発生し得るということであり、実際に過去において脆弱性が発見されている。

http://bugs.mysql.com/bug.php?id=41730

将来的に未知の脆弱性が知られる可能性を危惧するならば、明示的に「useServerPrepStmts=true」をJDBC接続URLに指定しておいた方がよいだろう。パフォーマンス等の問題については知見がないのだが、性能が変わってきたりするのだろうか。

TIMESTAMP型の仕様が特殊

http://dev.mysql.com/doc/refman/5.1-olh/ja/timestamp.html

詳細は仕様の方を見て頂きたいのだが、

  • ミリ秒が使えない
  • 自動初期化・自動更新が設定しだいで行われる
  • 初期状態ではNOT NULL属性が付与されており、NULLを入れたければ明示的にNULL属性を入れる必要がある

など、いわゆる他RDBMSJavaのTimestampクラスとは異質なクラスである。歴史的経緯という奴なのだろうが、正に「素人にはお勧めできない」日付型だと言える。

日付型が初期状態では00月、00日などを扱えてしまう。

これもMySQL固有の特徴で、

  • ダミーの日付型として「0000-00-00」つまり0000年00月00日を格納できてしまえる
  • 初期設定では日付型がかなり寛容(2011-02-31などを許容する)

という特性がある。無論厳格な日付型を受け入れるように設定する事が可能なのだが、DB間連携やアプリからの呼び出しでは注意する必要がありそうだ。

http://dev.mysql.com/doc/refman/5.1-olh/ja/date-and-time-types.html

ミリ秒を日付型で扱えない

これは上記のTimeStamp型の仕様とも関連するのだが、MySQLではDATETIME型もTIMESTAMP型も精度は秒までとなっている。

もしMySQLでミリ秒単位の時刻を取得したいなら、java.util.Date#getTime()で取得したミリ秒をMYSQLのBIGINT型に突っ込んで、取り出し時にはDateのコンストラクタにlong値として変換するが一番素直な実装に思える。

(以下、2012/09/24追記)

…とか言ってたら、MySQL 5.6では小数秒精度(ミリ秒・マイクロ秒)に対応するとの情報を見かけたので調べてみると…

http://dev.mysql.com/doc/refman/5.6/en/datetime.html

A DATETIME or TIMESTAMP value can include a trailing fractional seconds part in up to microseconds (6 digits) precision.

更に、小数秒精度に関する特設ページもあると。

http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html

小数秒精度の桁数は0(MySQL 5.5以前と互換)から最大6桁まで。テーブル定義時に決定できるみたいです。

マイクロ秒単位の精度が必要なケースにもMySQL 5.6が適用できる、って事になる訳ですね。一方で、小数秒精度を格納する領域が増えてパフォーマンスに影響する可能性やら、テーブル設計時の標準どうしようとか、アーキテクチャレベルでは色々考えに入れるべき事も増えてくるとは思います。

(以上、2012/09/24追記ここまで)

こうして見ると、日付型の問題が目を引くなあ…と。もちろん全ての問題を網羅できている訳ではないのだが、ひとまず備忘録として。