概要

割ともう書評も出揃ってる感がありますが、ようやく読み終わったので書こうと思います。

この本は SQL や DB 設計でやってしまいがちな、ダメダメなパターンを体系化して、名前をつけたものです。また、なぜそうなってしまうのか、どうやって回避するのか、使っても良い場合があるとしたらどういう場合か、も書いてあります。

PoEAA なんかもそうなのですが、わりと「知ってたわー、N年前から知ってたわー」という感想なのですが、それは僕自信がここ数年、それなりに真面目に DB 設計やったり SQL 書いたりしてたから言えるわけで、Nが 10 とか 20 とか年齢とかならそれに越したことはないと思います。

DB とか SQL とか自信ない人は是非読むべきです。DB 設計とか長くやってる人も、読んだほうがいいでしょうね。デザパタなんかと同様に、今後はパターン名知らないと、話が通じなくなっちゃう可能性がありますから。

経験の少ない人は「あ、これは SQL アンチパターンで見たやつだ!(なんとかゼミ風)」とかそんな感じで、熟練者にとっては、「オイ!この EAV で設計した奴どいつだ! F○CK!」とかそんな感じでお話ができるようになると、世の中少し幸せになるんじゃないかなー、と思うわけです。

IDリクワイアド(とりあえずID)

さてさて、中身ですが、書いてあることには概ね同意だし、上手くまとまってるなー、とは思うんですが、やっぱみんな色々言ってる「IDリクワイアド」ですかね。

  • 複合主キーを使うべきテーブルに「id」を付けるな、ってのはその通りだと思う
  • 自然キーも上手く使えってあるんだけど、これは反対
  • テーブル名が Bugs なら主キーは id じゃなくて、bug_id にしとけ、ってあるんだけど、これは微妙

自然キーですが、僕は基本的にサロゲートキーでやるべきだと思っています。自然キーには必要に応じて一意制約をはるのがいいかな。経験上、自然キーが本当にキーだったことは一度もありませんでした。何か追加の情報(リビジョンとか日付とか)入れれば主キーに大抵なるんですが、そんなんやるくらいなら、サロゲートキー入れたほうがよっぽど楽だと思います。

テーブル名とキー名ですが、これは規模によるんじゃないかな、と思います。テーブル数100以下くらいなら、一意なキー名つけれると思うので、JOIN でミスったり、 「SELECT *」するときにハマったりしないように、bug_id とかそんな感じにしといた方がいいかもいれませんね。

ただ、規模がでかくなると、どうしてもテーブル名が長くなってしまうので、そうすると、bug_id みたいな規則でキー名付けると、キー名がすごく長くなってしまいます。これはつらいので、id でいいんじゃね?と思います。JOIN でミスるのは、テーブル別名に「a」とか「b」とかイミフなのをつけるのが良くないのであって、ちゃんとテーブル別名「bugs」ってつければそういうミスは防げると思います。

さてさて、「IDリクワイアド」はこの辺にしといて。。。

キーレスエントリ(外部キー嫌い)

あとは、「キーレスエントリ」かな。これは言ってることは分かってて、DB設計者の立場としてはその通りだな、と思うんですが、(一方で僕は開発者でもあるので)、開発者としては「外部キー邪魔だな」と思うことがしばしばあります。テストデータ入れるのがすげー面倒くさくなるんですよね、外部キーあると。

また、DB管理者としては、外部キーあると、テーブルの変更が辛くなる場合がありますね。新しいテーブルを用意して、そっちと入れ替えるような変更ができなくなるんですよね。。。

外部キーに限らず、なのですが DBMS が持っている制約ってのはちょっとプア過ぎるよなー、と思います。チェック制約みたいなのも、テーブルまたぐようなチェックとかできないから、結局アプリでやるしかないし。とかそんな感じなので、バリデーションはアプリでやった方がいいんじゃないかなー、と思います。

外部キーは、「テストデータ出し入れするときだけ、一時的にオフるモード」とかあれば、もうちょい積極的に使いたいなー、とは思うんですが。

ファントムファイル(幻のファイル)

「ファントムファイル」も微妙じゃね?って意見をどっかで見たのですが、僕はこれアリだと思いました。「ファイルは常にディスクに置くべき、と考えるな。DB も使えるよ」っていう書き方だったので、それはまあその通りだよな、と思います。トランザクションを重視するか、Web サーバから見える所に置きたいか、によって使い分けるのがいいんじゃないかな、と思いました。

ただ、BLOB とか使う場合、RDBMS の設定とか、DB のドライバの設定とかを見直さないと、多分デフォルト設定だとデカいデータを置けないんじゃないかな、と思うんですが、その辺あんまちゃんと書いてないのが微妙というか、ちょっとアンフェアだな、と思いました。

まとめ

まあ最初に書いたとおりですけど、経験の少ない人にも熟練者にもおすすめできる本だと思います。まだ読んでない人は是非是非↓のアフィ付きリンクからポチって、GW 中に読んでみるべし!だと思います。

ちょい追記

コメントいただきました。ありがとうございます。

MySQLならFOREIGN_KEY_CHECKSとかあるんですがそういうのではなくて?

ごめんなさいごめんなさい。カジュアルかつ、いい加減に書きすぎました。データロードの問題は、問題の半分の半分くらいなんです。まず、データロード時に、FOREIGN_KEY_CHECKS とかそういうのを、いい感じに空気読んで設定してくれるツールが現状ありせん。

あと、もう一つの問題は FK 貼ると、テーブル A->B->C->D->E みたいな依存関係があるとして、テストしたい対象がテーブル E とかだったりすると、FK がうざくて仕方ありません。AからD までのデータを不整合無くちゃんと作るには、setup とかでうまくゴミデータを削除する必要が生じたりして、そんなことしてると一体僕は何をテストしてるんだろ?っていう気分になったりします。途中の B とか C とかに一意制約とかあったりして、主キー以外にも不整合を生じる要因とかあったりすると 2倍悲しかったりします。(うーん、このへんは伝わるか良く分かんないけど、僕はこの辺かなり悩みました。)

かと言って FK をテキトーにオフっちゃうと、 D->E みたいなやつをテストするときに、うっかり依存関係忘れちゃうし、こういうのムズいなー、と思います。

なんか Web 系の人は FK オフっちゃうほうが多数派っぽくて、業務系の人はあんま blog 書いてないから動向良く分かんなくて、結局この辺の必勝法良く分かんないなー、と思います。

DELETE ON CASCADE とかいい感じに設定するといい感じになる必勝法がありそうな気がするんですけど、FK オフらずかつ、テストコードでテストデータロードしてたり本番環境からマスタデータの引き上げとかやってる人いたら、どんな感じでやっているのか、是非是非教えてほしいなぁ、と思います。