SQLアンチパターン

| Comments

※過去記事です。

SQLアンチパターン

さて、今日はこの本です。 最近、本のレビューを上げられていないのですが、別にサボっているわけじゃなくて技術書とかやたら難解な哲学書に時間を取られてるからです。普通の本と比べてこれらの本は全然読み進められないですね。。。

さて、本書は具体的な事例を元に、RDB設計においてのアンチパターン(やってはいけないやり方)とTipsが紹介されています。一つ一つ取り上げて思い出しながらまとめます。が、これだけ読んでも絶対ピンと来ないと思うので、興味を持った人は本書をお手にとって頂ければ。今回はあくまで自分用のまとめになると思います。

1 信号無視

データ一つに対して複数のIDをひもづける場合。

アンチパターン:VARCHARなどで、カンマ区切りでIDを入れていくこと。検索や集約関数が複雑になってしまう。VARCHARの文字数制限に依存してしまう。

解決策: 多対多の交差テーブルを用意する。

2 ナイーブツリー

コメントへのレスなど、階層構造が未定のものの設計。

アンチパターン:常に親のみに依存する。検索クエリが、有限値までしか機能しない。

解決策: 代替ツリーモデル採用 ・経路列挙 ・入れ子集合 ・閉包テーブル

3 とりあえずID

主キーの目的は一意性を保つため。データの重複が起きては全く意味が無い。

アンチパターン: 全てのテーブルにID列を用いる。

解決策:ほんとうに意味がある列なのかを考え、臨機応変に対応するしかない。

4 外部キー嫌い

アンチパターン: 外部キー制約を利用しない。ミスを想定・検証できない。孤児(どこからも参照されないデータ)が生じる。オーバーヘッドが生じるというが、エラーチェックやバグ検証に比べれば微々たるもの。

解決策:きちんと制約を設ける。

5 様々な属性値を使いたい。

後から追加できるような様々な属性値を使いたい。

アンチパターン:汎用的な属性テーブルを使用する。 検索や集約のクエリが複雑になる。データの整合性の確認ができない。

解決策:事前に入りうるデータを想定すべき。(Check制約などを使い制限) 別途テーブルを用意して属性値を並べる。(項目が増えるときはそこだけ修正する。) ### 6 複数の親テーブルを、条件に応じて参照したい。

アンチパターン:列を一つ追加してそこの値に応じて参照テーブルを変える。

  • クエリが行いづらい。
  • 外部キー制約が出来ない。

解決策: 参照関係を逆にする。(交差テーブルを用いて、複数の子を持つようにする。)

7 複数の値を持つ属性を格納する。

アンチパターン:複数の列を定義する 列の数までしか追加できない。 Nullが多く入り、検索が困難。

解決策: 交差テーブルを用意する。

8 メタデータドリブン

データが大量に溜まってしまった状態。処理が遅くなってしまっているので、各年ごと(or〜ごと)のデータを上手く活用したい。

アンチパターン:テーブルや列を増やしていく。

解決策:パーティショニングと正規化を行う。

9 丸め誤差

小数値を扱う場合

アンチパターン:Float型を使う。

解決策:numericデータ型を使う。制度やスケールを調整することで正しい数値を利用できる。

10 列の値を特定の値に限定したい

しかし、その値が増減する可能性がある。(例:勤務地データ 東京・大阪・名古屋・札幌(new))

アンチパターン:CHECK制約(限定する値で縛る)→拡張が効かない、移植が難しい。変更しづらい。

解決策:別に列テーブルを作って参照する。 (ただし、性別や月次などのように値が決まりきってる場合はCheckでよい)

11画像など大容量データの紐付け。

アンチパターン:物理ファイルの使用を必須と思い込む。

一般に対処法は2つある。BLOB型に入れるか、物理ファイルへのパスを保管するか。前者は不規則なデータ量の時にDBの容量がかさむ、編集がしづらい。後者は、物理ファイルのデータはバックアップやロールバックが行いにくく、整合性を保てない。

解決策:必要に応じてBLOB型も検討する。

12 indexをやみくもに定義する。

アンチパターン:なんでもかんでもindexを定義する。→毎回indexを更新する必要があり、重くなる。あまり効率化されない。

解決策:必要なところにのみindexをつけることを徹底する。

13 列で欠けている値を区別する 

アンチパターン:NULLと一般値を混同する。→NULLを用いると論理式が複雑になる。一般値で代用するときは、その値の正当性が保証されるか判断する。

解決策:NULLが入らないような設計。そうでなければNULLを一意の値として用いる。

14 非グループ化列を参照する。

アンチパターン:非グループ化された列(式)を参照してしまう。

解決策:SQLに甘えず、曖昧さを排除したselect文を記述する。

15 ランダムセレクション

アンチパターン:データ量が大きい中でランダムに行をセレクトすると重くなる。→全ての行を配置しなおしたりするから。

解決策:値が連続している場合→1〜MAX値までの間で、主キーでランダムに取る。 飛び飛びの値の場合→欠番の行を取得するなど。

(キー列のリストを受け取って乱数にかけるのが速い。indexもあるだろうし。)

16 全文検索を行う。

アンチパターン:LIKEを用いる。

解決策:適切な検索ツールを使う。(各DBベンダーが拡張機能を提供している。フルテキストインデックスなど。)

17 スパゲッティクエリ

アンチパターン:複雑なものを一度に取得しようとする。

解決策:一個ずつやればいい。

18 列名はちゃんと命名しろ

アンチパターン:SYA_IDとか

解決策:見て意味が理解できなければ意味が無い。

19 パスワード

アンチパターン:平文で残すな。

解決策:ハッシュ値を格納して、チェックのみ行う。(≒暗号化)

20 SQLインジェクション

アンチパターン:何も対策しない。

解決策:プログラムを作る際はサニタイズする。

21 擬似キー(IDとか。重複を防ぐ役割)

アンチパターン:欠番を気にする。

解決策:int型だけでものすごい数があるので気にしない。

Comments