SQLアンチパターン メモ
DBまわりを中心に扱うことになったので、言わずと知れた名著 SQLアンチパターン を読みました。各章ごとにメモがてら大事そうな箇所だけここに書いておいて、業務で出くわす場面があればここをインデックスに本書を読もうと思い雑にまとめています。
I部データベース論理設計のアンチパターン
1章 ジェイウォーク(信号無視)
一つのカラムに複数の値を入れようとするのは危ない、スキーマ設計を見直すべき。
2章 ナイーブツリー(素朴な木)
素朴=思慮の浅い、設計不足。階層構造を扱う方法はバリエーションがあるので、ユースケースごとにメリデメを評価すべし。閉包テーブル(Closure Table)がナウイ(2013)
3章 IDリクワイアド(とりあえずID)
自然キー(Natural Key)仕様上レコードを一意に特定できる値。エラーコード ACC-0001みたいな。
代理キー(Surrogate Key)自動的に割り振る意味を持たない値。Railsで勝手につくid
自然キーや複合キーで一意性を表現できるテーブルに代理キーを無理につける必要はない。一方で規約に乗るメリットもある。
4章 キーレスエントリ(外部キー嫌い)
予期せぬ孤児データの発生や参照整合性(親テーブルの値と一致しているか)を自前で担保する大変さがあるので外部キーを使おう。
5章 EAV(エンティティ・アトリビュート・バリュー)
自由なKey/ValueをRDBに格納するのはやめよう。可変な属性値があるときはサブタイプを取り入れよう。(例: Issuesテーブルを親とした=issue_idを持ったBugsテーブルとFeatureRequestsテーブルを作る)
6章 ポリモーフィック関連
親テーブルを複数のテーブルから選択できるような設計はよくない。(例: CommentsはBugsかFeatureRequestsを親に持てる) 交差テーブルを使うなどして対処しよう。
7章 マルチカラムアトリビュート(複数列属性)
tag1,tag2,tag3みたいなカラム定義は避けてTagテーブルを作ろう。
8章 メタデータトリブル(メタデータ増殖)
Bug2011,Bug2012,…みたいなテーブルを追加するくらいならシャーディングしよう。ふだんあまり参照されないカラムは別テーブルに切り出そう(垂直パーティショニング)
II部 データベース設計のアンチパターン
9章 ラウンディングエラー(丸め誤差)
実数を扱う時はDECIMALを使おう。
10章 サーティワンフレーバー(31のフレーバー)
確実にバリエーションが変わらないときだけENUMを使うべき。右/左とか。
それ以外は外部テーブルに切り離した方が変更に強い。
11章 ファントムファイル(幻のファイル)
画像はファイルパスを文字列で格納せずにBLOBに直接保存しよう。DB外に保存したデータはトランザクションにおける整合性を保てなくなる。
12章 インデックスショットガン(闇雲インデックス)
MENTORの原則に基づいてクエリチューニングを行おう。
Mesure(測定): スロークエリを調べる
Nominate(指名): Indexが効いてないクエリを特定する
Test : 改善の before:afterをまとめる
Optimize : DBのパラメータチューニング
Rebuild: OPTIMIZE TABLE
Ⅲ部 クエリのアンチパターン
13章 フィア・オブ・ジ・アンノウン(恐怖のアンノウン)
NULLは値が何も入っていない、分からないことを表現するために使う。WHERE条件でNULLを使った比較はしない。
14章 アンビギュアスグループ(曖昧なグループ)
集約関数(MAX, MIN)で取ってくる列以外の列を取ってくるのは単一値の原則に反する。外部結合など解決策はあるけど大体はパフォーマンスが良くないので、本当に必要な列なのか考えるべし。
15章 ランダムセレクション
ランダムに一行取りたい、みたいなとき。ランダムアクセスは非効率定期。window関数とかTABLSAMPLEとか、ベンダーごとに解決策が用意されてることが多い。
16章 プアマンズ•サーチエンジン(貧者のサーチエンジン)
あいまい検索をMySQLで頑張りすぎない。トリガーとかストアドプロシージャーが紹介されてるけどメンテコストを考えたくない。
17章 スパゲッティクエリ
1行のクエリで解決しようとして複雑になりすぎるのは良くない。ORMなんかを使っていると意図せずそうなってしまうことがある。
18章 インプリシットカラム(暗黙の列)
SELECT * はやめよう。YAGNI: You Ain’t Gonna Beed It
Ⅳ部 アプリケーション開発のアンチパターン
19章 リーダブルパスワード(読み取り可能パスワード)
パスワードのやり取りは、ユーザー -(HTTPs) -> アプリケーション -(ソルト+ハッシュ)->データベース。
20章 SQL インジェクション
ユーザーからの入力が直接クエリを書き換えられる実装にしてはいけない。プリペアドステートメントを使おう。レビュー大事。
21章 シュードキー•ニートフリーク(擬似キー潔癖症)
擬似キーの欠番は埋める必要ない。欠番が気になる上司にはきちんと説明する。
22章 シー•ノー•エビル(臭いものに蓋)
ちゃんとエラーハンドリング書こうな。
23章 ディプロマティック•イミュニティ(外交特権)
DBAもアプリ開発者と同等の開発スキルや知見を持っておくべき。一方でアプリ開発者も、設計段階からデータ構造を理解しておくべき。“アプリケーションの文書化の価値は低いが、データベースの文書化の価値はある。”
24章 マジックビーンズ(魔法の豆)
アクティブレコード、DAOとドメインロジックを分けて実装する、疎結合にすることで保守性の高いコードになる。
フレームワークは初速が出る一方、あとからリファクタリングする計画を立てておくのが大切。
25章 砂の城
事前の障害対策をどうやるか。
ベンチマークを取って、あらかじめシステムの性能限界を把握しておく
本番環境と同等のテスト環境を用意しておく(マシンスペック、データサイズ)
コストとトレードオフだが十分に冗長構成を取っておく
定期的なバックアップ
使用するRDBMSの例外処理を把握しておく