正規化は正義
正規化が絶対的な正義だった時代がある。ストレージのコストが高く、同じデータを複数のテーブルで保持するなんてもってのほか。更新するにも同時に複数のテーブルを更新しないとならない。だから、第一正規形から第三正規形までをがっつり学ばせられて、当然それに沿うようにテーブルを設計するのが絶対の正義で、守らぬ者は非国民である、ぐらいの扱いをされた。
正規化は遅い
正規化されているので、読み出す時にはJoinしたりサブクエリーを活用して、複数のテーブルから必要なデータをかき集める。AS/400でRPG/400を書いてる時にも「物理ファイル」と「論理ファイル」という存在があって(この「物理」「論理」はおそらく日本語訳が良くない)、複数の物理ファイルから構成される論理ファイルを読むなんてやってたが、まああれはOUTER JOINだったんだよな。
いずれにしても、読み出す時に高いコストを支払うことになり、とても遅い。求められる速度が秒ではなくミリ秒、あるいはそれ以下なんて話をしている時代に、OUTER JOINなんてしてる場合ではない。
ストレージは安い
2008年に買ったSSDは80GBで約8万円だったが、昨年ほぼ同じ値段で8TBのSSDを買った。容量単価は100分の1だ。さらに言えば、1996年に買ったHDDは250MBで数万円をはたいた記憶があるけれど、今同じお金を払ったら16TBぐらいか?
いずれにしてもストレージは容量単価が劇的に下がったし、CPUやメモリにも同じことが言える。コストの面からは、データをいくらか冗長に保持することはもはや全く問題ではない。
冗長で良いんだよ
現在、最もコストが高いのはおそらく時間。時間を短縮するために、ストレージやCPUやネットワークや、その他諸々をいかに効率良く投じるかについて、よくよく考える必要がある。が、鉄板構成はとっくに決まってて、あとは巨人の肩に乗れば良い。
Azure Cosmso DB for NoSQLでデータをぶっ込んで、そのデータの影響範囲についてはChangeFeedで反映しちゃう。
例えばゲームだと、プレイヤーがギルドに参加する。参加したギルドのIDをプレイヤーのドキュメントに追加するとChangeFeedがFunctionを呼び出し、そのFunctionでギルドのドキュメントにプレイヤーのIDや名前などを追加する。次にギルドのメンバーの一覧を表示する時には、表示するために必要なデータはギルドのドキュメントに全てふくまれているから、そのドキュメント1つだけを読み出せば事足りる。
この場合、プレイヤーのIDや名前といったデータは、複数のコレクションに含まれている。そう、プレイヤーとギルドのドキュメントだ。でも「それが何か問題でも?」。ストレージのコストは安いし、複数のドキュメントを更新する仕組みを作るのも簡単だ。これでミリ秒のレスポンスが得られるのに、どうしてRDBMSのチューニングやクエリーの最適化に拘る? もちろんトランザクションが必要な場面などが消えて無くなるわけではないから、RDBMSの出番が無くなるわけではない。
でも、何でもかんでもRDBMSに投げるのはもうやめよう。ギルドメンバーのテーブルにあるプレイヤーIDをとってきて、プレイヤーのテーブルからプレイヤーの名前を持ってきて…、そんなSELECT文を発行するのはもうやめよう。それは、昔のやり方だ。