『SQLアンチパターン』
https://gyazo.com/532c77d1d6035f0e88b8f9c299c6a541
2013/1/26
Bill Karwin 著
@t-wada 監修
和田省二 監修
児島修 翻訳
原著
『SQL Antipatterns』
https://www.amazon.com/dp/1934356557
オライリー・ジャパン
最近改訂版(?)が出たらしい
タイトルが意味不明すぎない?「Volume 1」ってなんだよmrsekut.icon
『SQL Antipatterns, Volume 1』
https://www.amazon.com/dp/1680508989
2022/11
内容はそんなに変わってない模様
/mrsekut-book-4873115892
感想
DB、SQLの基礎を知っていれば誰でも読めるレベルの内容
例示が具体的で親切
各章は独立しているのでどこからでも読める
パターンによっては、「こんなアホな設計、逆に思いつかんわ」というのもある
軽く読んで、パターンを知ってリンクを付けて、実際に起きそうになった時に熟読すれば良さそうmrsekut.icon
アンチパターンの命名(章名)は、分かりづらいので微妙ではという気はする
この本が有名なのでググればヒットするが、初見者には直感的ではない
タイトルはSQLだが、以下らへんについて書かれている
論理設計
物理設計
SQL
/mrsekut-book-4873115892/012 (監訳者まえがき)
/mrsekut-book-4873115892/018 (はじめに)
サンプルデータベース
/mrsekut-book-4873115892/023
I部 データベース論理設計のアンチパターン
1章 ジェイウォーク(信号無視)
/mrsekut-book-4873115892/042 (1章 ジェイウォーク(信号無視))
多対多を表現するために、カンマ区切りを使わない
0から設計するならこんなことしないけど、途中で仕様が変わったらありえなくもないのかmrsekut.icon
2章 ナイーブツリー(素朴な木)
/mrsekut-book-4873115892/052 (2章 ナイーブツリー(素朴な木))
tree構造のデータをtableで表現する
3章 IDリクワイアド(とりあえずID)
/mrsekut-book-4873115892/072 (3章 ID リクワイアド(とりあえずID))
主張がふわふわしてる章だなmrsekut.icon
あらゆるtableにサロゲートキーであるidを付けるというアンチパターン
どのデータを用いて主キーを設計するか
4章 キーレスエントリ(外部キー嫌い)
/mrsekut-book-4873115892/082 (4章 キーレスエントリ(外部キー嫌い))
外部キー制約を使わないことに対する指摘
普通の外部キー制約の話
5章 EAV(エンティティ・アトリビュート・バリュー)
/mrsekut-book-4873115892/090 (5章 EAV (エンティティ・アトリビュート・バリュー))
問題意識はOR型をtable上でどう表現するかと同じ
特にgroupbyで計算する時に
同じcolumnにないといけない
比較可能なフォーマットになってないといけない
というのもある
解決策が微妙なものが多いな
それを解決策と呼ぶべきじゃないでしょ、という感じのが多い
6章 ポリモーフィック関連
/mrsekut-book-4873115892/106 (6章 ポリモーフィック関連)
ポリモーフィック関連というアンチパターン
7章 マルチカラムアトリビュート(複数列属性)
/mrsekut-book-4873115892/120 (7章 マルチカラムアトリビュート(複数列属性))
「1つの投稿に、複数のタグを付けられる」のような仕様の時にどうtableを作るか
tag1,tag2,tag3のように上限を決め打ちしてcolumnを作るというアンチパターン
ここにきて急に基本的すぎるmrsekut.icon
8章 メタデータトリブル(メタデータ大増殖)
/mrsekut-book-4873115892/128 (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章 ラウンディングエラー(丸め誤差)
/mrsekut-book-4873115892/142 (9章 ラウンディングエラー(丸め誤差))
IEEE754の小数計算の誤差の話
FLOAT型を使うと誤差が生じるので注意する
where hourly_rate = 59.95のように書いた時に、
DB内に保存されている値が、59.950000762939のようになっていると、当然一致しない
where abs(hourly_rate - 59.95) < 0.000001のように書くらしい
SUM関数で集約した時に誤差が出るなど
どうするか?
NUMERIC型やDecimal型を使うなどする
精度とスケールを指定できる
10章 サーティワンフレーバー(31のフレーバー)
/mrsekut-book-4873115892/150 (10章 サーティワンフレーバー (31 のフレーバー))
ある選択肢のみ許容するcolumnを定義する際の方針
11章 ファントムファイル(幻のファイル)
/mrsekut-book-4873115892/158 (11章 ファントムファイル(幻のファイル))
画像をDBで管理する際に、
画像本体はS3などの外部サービスに入れて、
そのURLをDBに入れる
というのが一般的だが、著者はこれをアンチパターンと呼んでる
著者自身も、この主張が少数派であることは認識してるっぽい
これ、当然だと思いすぎてメリデメを考えたこともなかったなmrsekut.icon
やることはないにしても知っておいて損はなさそう
DBにBLOB型で画像を保存する
初学者がこの章読むと真に受けそうだなmrsekut.icon
12章 インデックスショットガン(闇雲インデックス)
/mrsekut-book-4873115892/168 (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)
/mrsekut-book-4873115892/184 (13章 フィア・オブ・ジ・アンノウン (恐怖のunknown))
適当な一般値としてNULL (SQL)を使うことについて
NULLの使用は避けるべきだが、かといって-1とか9999のような初期値を用意するのもおかしい
解決策の章、解決策の話ししてなくない?
NULLの説明をしてるだけ
この章微妙だなmrsekut.icon
14章 アンビギュアスグループ (曖昧なグループ)
/mrsekut-book-4873115892/194 (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章 ランダムセレクション
/mrsekut-book-4873115892/204 (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章 プアマンズ・サーチエンジン (貧者のサーチエンジン)
/mrsekut-book-4873115892/212 (16章 プアマンズ・サーチエンジン (貧者のサーチエンジン))
SQLで全文検索することの問題点
ベンダー拡張
MySQL, Oracle, Microsoft SQL Server, PostgreSQL, SQLiteそれぞれの解説
転置インデックスの自作
一度検索したことのあるクエリをキャッシュする感じのtableをもう1個作る
17章 スパゲッティクエリ
/mrsekut-book-4873115892/226 (17章 スパゲッティクエリ)
複雑な処理を、1つのSQLで書こうとする、というアンチパターン
デカルト積になるのは、単にJOINの仕方がおかしいからでは?mrsekut.icon
クエリが大きいことと直接は関係なくない?
1つのSQLのクエリの大きさ
なんか例が極端だなmrsekut.icon
「レポート」を例にしてるのも逃げてる感じがある
1回きりのレポートを出したいだけならパフォーマンスはほぼ問題にならない
パフォーマンスが問題になるのはアプリケーションでの話であって、それを例に持ってくるべき
18章 インプリシットカラム (暗黙の列)
/mrsekut-book-4873115892/236 (18章 インプリシットカラム (暗黙の列))
「タイプ数を減らすため」という目的で、ワイルドカード*を使わない
SQLでは省略せずに書く
型がちゃんとしたORMを使ってたら大丈夫mrsekut.icon
IV部 アプリケーション開発のアンチパターン
19章 リーダブルパスワード (読み取り可能パスワード)
/mrsekut-book-4873115892/246 (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章 マジックビーンズ (魔法の豆)
/mrsekut-book-4873115892/302 (24章 マジックビーンズ (魔法の豆))
MVCのMがActive Recordになっている、というアンチパターン
MVCとActive Recordの話題はあまり興味がないのでほぼ読んでないmrsekut.icon
25章 砂の城
/mrsekut-book-4873115892/318 (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 参考文献
索引
#スクボ読書化した本