generated at
『SQLアンチパターン』

2013/1/26
@t-wada 監修
和田省二 監修
児島修 翻訳
原著

最近改訂版(?)が出たらしい
タイトルが意味不明すぎない?「Volume 1」ってなんだよmrsekut
2022/11
内容はそんなに変わってない模様



感想
DB、SQLの基礎を知っていれば誰でも読めるレベルの内容
例示が具体的で親切
各章は独立しているのでどこからでも読める
パターンによっては、「こんなアホな設計、逆に思いつかんわ」というのもある
軽く読んで、パターンを知ってリンクを付けて、実際に起きそうになった時に熟読すれば良さそうmrsekut
アンチパターンの命名(章名)は、分かりづらいので微妙ではという気はする
この本が有名なのでググればヒットするが、初見者には直感的ではない

タイトルはSQLだが、以下らへんについて書かれている
論理設計
物理設計
SQL





サンプルデータベース

>I部 データベース論理設計のアンチパターン

1章 ジェイウォーク(信号無視)
0から設計するならこんなことしないけど、途中で仕様が変わったらありえなくもないのかmrsekut



2章 ナイーブツリー(素朴な木)



3章 IDリクワイアド(とりあえずID)
主張がふわふわしてる章だなmrsekut
あらゆるtableにサロゲートキーである id を付けるというアンチパターン


4章 キーレスエントリ(外部キー嫌い)
外部キー制約を使わないことに対する指摘
普通の外部キー制約の話



5章 EAV(エンティティ・アトリビュート・バリュー)
特にgroupbyで計算する時に
同じcolumnにないといけない
比較可能なフォーマットになってないといけない
というのもある
解決策が微妙なものが多いな
それを解決策と呼ぶべきじゃないでしょ、という感じのが多い



6章 ポリモーフィック関連
ポリモーフィック関連というアンチパターン




7章 マルチカラムアトリビュート(複数列属性)
「1つの投稿に、複数のタグを付けられる」のような仕様の時にどうtableを作るか
tag1 , tag2 , tag3 のように上限を決め打ちしてcolumnを作るというアンチパターン
ここにきて急に基本的すぎるmrsekut



8章 メタデータトリブル(メタデータ大増殖)
8.1 目的:スケーラビリティを高める
8.2 アンチパターン:テーブルや列をコピーする
8.2.1 テーブルの増殖
8.2.2 データの整合性を管理する
8.2.3 データの同期
8.2.4 一意性の保証
8.2.5 テーブルをまたいだクエリ実行
8.2.6 メタデータの同期
8.2.7 参照整合性の管理
8.2.8 メタデータトリブル列の特定
8.3 アンチパターンの見つけ方
8.4 アンチパターンを用いてもよい場合
8.5 解決策:パーティショニングと正規化を行う
8.5.1 水平パーティショニングの使用
8.5.2 垂直パーティショニングの使用
8.5.3 従属テーブルの導入

>II部 データベース物理設計のアンチパターン

9章 ラウンディングエラー(丸め誤差
FLOAT 型を使うと誤差が生じるので注意する
where hourly_rate = 59.95 のように書いた時に、
DB内に保存されている値が、 59.950000762939 のようになっていると、当然一致しない
where abs(hourly_rate - 59.95) < 0.000001 のように書くらしい
SUM関数で集約した時に誤差が出るなど
どうするか?
NUMERIC型Decimal型を使うなどする
精度とスケールを指定できる


10章 サーティワンフレーバー(31のフレーバー)



11章 ファントムファイル(幻のファイル)
画像をDBで管理する際に、
画像本体はS3などの外部サービスに入れて、
そのURLをDBに入れる
というのが一般的だが、著者はこれをアンチパターンと呼んでる
著者自身も、この主張が少数派であることは認識してるっぽい
これ、当然だと思いすぎてメリデメを考えたこともなかったなmrsekut
やることはないにしても知っておいて損はなさそう
初学者がこの章読むと真に受けそうだなmrsekut




12章 インデックスショットガン(闇雲インデックス)
12.1 目的:パフォーマンスを最適化する
12.2 アンチパターン:闇雲にインデックスを使用する
12.2.1 インデックスをまったく定義しない
12.2.2 インデックスを多く定義し過ぎる
12.2.3 インデックスが役立たないとき
12.3 アンチパターンの見つけ方
12.4 アンチパターンを用いてもよい場合
12.5 解決策:「MENTOR」の原則に基づいて効果的なインデックス管理を行う
12.5.1 Measure(測定)
12.5.2 Explain(解析)
12.5.3 Nominate(指名)
12.5.4 Test(テスト)
12.5.5 Optimize(最適化)
12.5.6 Rebuild(再構築)


>III部 クエリのアンチパターン

13章 フィア・オブ・ジ・アンノウン (恐怖のunknown)
適当な一般値としてNULL (SQL)を使うことについて
NULLの使用は避けるべきだが、かといって -1 とか 9999 のような初期値を用意するのもおかしい
解決策の章、解決策の話ししてなくない?
NULLの説明をしてるだけ
この章微妙だなmrsekut




14章 アンビギュアスグループ (曖昧なグループ)
14.1 目的:グループ内で最大値を持つ行を取得する
14.2 アンチパターン:非グループ化列を参照する
14.2.1 単一値の原則( Single-Value Rule)
14.2.2 SQLがクエリの意図を汲んでくれるとは限らない
14.3 アンチパターンの見つけ方
14.4 アンチパターンを用いてもよい場合
14.5 解決策:曖昧でない列を使用する
14.5.1 関数従属性のある列のみにクエリを実行する
14.5.2 相関サブクエリを使用する
14.5.3 導出テーブルを使用する
14.5.4 JOINを使用する
14.5.5 他の列に対しても集約関数を使用する
14.5.6 グループごとにすべての値を連結する

15章 ランダムセレクション
15.1 目的:サンプル行をフェッチする
15.2 アンチパターン:データをランダムにソートする
15.3 アンチパターンの見つけ方
15.4 アンチパターンを用いてもよい場合
15.5 解決策:特定の順番に依存しない
15.5.1 1と最大値の間のランダムなキー値を選択する
15.5.2 欠番の穴の後にあるキー値を選択する
15.5.3 すべてのキー値のリストを受けとり、ランダムに 1つを選択する
15.5.4 オフセットを用いてランダムに行を選択する
15.5.5 ベンダー依存の解決策

16章 プアマンズ・サーチエンジン (貧者のサーチエンジン)
SQLで全文検索することの問題点
ベンダー拡張
MySQL, Oracle, Microsoft SQL Server, PostgreSQL, SQLiteそれぞれの解説
一度検索したことのあるクエリをキャッシュする感じのtableをもう1個作る


17章 スパゲッティクエリ
複雑な処理を、1つのSQLで書こうとする、というアンチパターン
デカルト積になるのは、単にJOINの仕方がおかしいからでは?mrsekut
クエリが大きいことと直接は関係なくない?
なんか例が極端だなmrsekut
「レポート」を例にしてるのも逃げてる感じがある
1回きりのレポートを出したいだけならパフォーマンスはほぼ問題にならない
パフォーマンスが問題になるのはアプリケーションでの話であって、それを例に持ってくるべき



18章 インプリシットカラム (暗黙の列)
「タイプ数を減らすため」という目的で、ワイルドカード * を使わない
型がちゃんとしたORMを使ってたら大丈夫mrsekut




>IV部 アプリケーション開発のアンチパターン

19章 リーダブルパスワード (読み取り可能パスワード)
19.1 目的:Passwordのリカバリーとリセットを行う
19.2 アンチパターン:パスワードを平文で格納する
19.2.1 パスワードの格納
19.2.2 パスワードの認証
19.2.3 パスワードを電子メールで送信する
19.3 アンチパターンの見つけ方
19.4 アンチパターンを用いてもよい場合
19.5 解決策:ソルトを付けてパスワードハッシュを格納する
19.5.1 ハッシュ関数を理解する
19.5.2 SQLでのハッシュの使用
19.5.3 ハッシュにソルトを加える
19.5.4 SQLからパスワードを隠す
19.5.5 パスワードをリカバリーするのではなく、リセットする

20章 SQL Injection
20.1 目的:動的 SQLを記述する
20.2 アンチパターン:未検証の入力をコードとして実行する
20.2.1 アクシデントは起きる
20.2.2 ウェブ最大のセキュリティ脅威
20.2.3 対処法の追求
20.3 アンチパターンの見つけ方
20.4 アンチパターンを用いてもよい場合
20.5 解決策:誰も信用してはならない
20.5.1 入力のフィルタリング
20.5.2 動的値のパラメータ化
20.5.3 動的値を引用符で囲む
20.5.4 ユーザーの入力をコードから隔離する
20.5.5 他の開発者にコードをレビューしてもらう

21章 シュードキー・ニートフリーク(疑似キー潔癖症)
21.1 目的:欠番を詰める
21.2 アンチパターン:隙間を埋める
21.2.1 欠番を割り当てる
21.2.2 既存行に番号を振り直す
21.2.3 データ不一致の元
21.3 アンチパターンの見つけ方
21.4 アンチパターンを用いてもよい場合
21.5 解決策:疑似キーの欠番は埋めない
21.5.1 行のナンバリング
21.5.2 GUIDの使用
21.5.3 最も重要な問題

22章 シー・ノー・エビル(臭いものに蓋)
22.1 目的:簡潔なコードを書く
22.2 アンチパターン:肝心な部分を見逃す
22.2.1 診断せずに判断する
22.2.2 見逃しがちなコード
22.3 アンチパターンの見つけ方
22.4 アンチパターンを用いてもよい場合
22.5 解決策:エラーから優雅に回復する
22.5.1 リズムを維持する
22.5.2 ステップをたどり直す

23章 ディプロマティック・イミュニティ(外交特権)
23.1 目的:ベストプラクティスを採用する
23.2 アンチパターン: SQLを特別扱いする
23.3 アンチパターンの見つけ方
23.4 アンチパターンを用いてもよい場合
23.5 解決策:包括的に品質問題に取り組む
23.5.1 文書化
23.5.2 バージョン管理
23.5.3 テスティング
23.5.4 複数のブランチを扱う

24章 マジックビーンズ (魔法の豆)
MVCのMがActive Recordになっている、というアンチパターン
MVCとActive Recordの話題はあまり興味がないのでほぼ読んでないmrsekut



25章 砂の城
25.1 目的:サービスの安定稼働
25.2 アンチパターン:想定不足
25.3 アンチパターンの見つけ方
25.4 アンチパターンを用いてもよい場合
25.5 解決策
25.5.1 ベンチマーク
25.5.2 テスト環境の構築
25.5.3 例外処理
25.5.4 バックアップ
25.5.5 高可用性
25.5.6 ディザスタリカバリ
25.5.7 運用ポリシーの策定


>V部 付録
付録A 正規化のルール
A.1 リレーショナルとは何か
A.1.1 行に上下の順番がない
A.1.2 列に左右の順番がない
A.1.3 重複行を許可しない
A.1.4 すべての列は 1つの型を持ち、各行に 1つの値を持つ
A.1.5 行に隠されたコンポーネントがない
A.2 正規化の神話
A.3 正規化とは何か
A.3.1 第 1正規形
A.3.2 第 2正規形
A.3.3 第 3正規形
A.3.4 ボイスコッド正規形
A.3.5 第 4正規形
A.3.6 第 5正規形
A.3.7 他の正規形
A.4 正規化は常識的なもの
付録B 参考文献
索引