SQLアンチパターンの内容をまとめます その2
内容まとめ
9章 ラウンディングエラー(丸め誤差)
FLOAT型を使うことにより、丸め誤差が発生してしまうアンチパターンです。
解決策
NUMERIC型を使いましょう!
ALTER TABLE Bugs ADD COLUMN hours NUMERIC(9, 2)
NUMERIC型は、FLOAT型とは違い丸め誤差が発生しません。
10章 サーティーワンフレーバー(31のフレーバー)
テーブルに格納する値がすでに全て判明している場合に、安易にCHECK
制約やENUM
を使用してしまうというアンチパターンです。
後日新たに値を追加することになってしまうと、面倒なことになります。
解決策
別テーブルを作成し、外部キー制約を付与しましょう!
BugStatusテーブルCREATE TABLE BugStatus ( status VARCHAR(20) PRIMARY KEY );
BugsテーブルCREATE TABLE bugs ( status VARCHAR(20), FOREIGN KEY (status) REFERENCES BugStatus(status) ON UPDATE CASCADE );
11章 ファントムファイル(幻のファイル)
カラムの値としてサーバー上のファイルのパスを保持してしまう、というアンチパターンです。
もしカラムの値が消えてしまったら、どのファイルがどこにあるかわからなくなってしまいます!
解決策
BLOB型を採用しましょう!
BLOB型であれば、画像などのバイナリデータをそのまま格納することができます。
12章 インデックスショットガン(闇雲インデックス)
インデックスについて理解していないために発生するアンチパターンです。
具体的には以下のような状況が起きてしまいます。
- インデックスを全く使用しない
- インデックスを多く定義しすぎるか、役に立たないインデックスを定義してしまう
- インデックスを活用しないクエリを使用してしまう
解決策
MENTOR原則にもとづいて効果的なインデックス管理を行いましょう!
MENTOR原則とは、以下の頭文字をとった言葉です。
- Measure(測定)
- Explain(解析)
- Nominate(指名)
- Test(テスト)
- Optimize(最適化)
- Rebuild(再構築)
13章 フィア・オブ・ジ・アンノウン(恐怖のunknown)
null
を一般値として扱ってしまう、というアンチパターンです。
計算式などでnull
が絡むと、思いがけない結果になるというのはよくある話だと思います。
だからといってnull
を必要以上に避けてしまうと、これまたアンチパターンとなります。
解決策
null
を一意な値として扱いましょう!
null
を計算に使ったり、結合したりしてはいけません。
必要に応じてNOT NULL
制約を使用しましょう。
14章 アンビギュアスグループ(曖昧なグループ)
GROUP BY
で集計した場合にMAX
関数を使用すると、想定通りの最大値が得られない、というアンチパターンです。
解決策
関数従属性のある列のみにクエリを実行しましょう!
GROUP BY
で指定した列のみを取得する、というイメージです。
他にも、サブクエリを使用することでも解決できます。
15章 ランダムセレクション
ランダムにソートしてしまうことによりパフォーマンスが落ちる、というアンチパターンです。
以下のようなクエリが一例です。
ランダムにソートしてしまうクエリSELECT * FROM Bugs ORDER BY RAND() LIMIT 1;
RAND
関数を使用することで、インデックスが効かなくなってしまいます。
解決策
欠番のないテーブルであることが保証されているのであれば、以下のクエリが最適です。
欠番がないテーブルの前提SELECT b1.* FROM Bugs b1 INNER JOIN ( SELECT CEIL(RAND() * (SELECT MAX(bug_id) FROM Bugs)) rand_id ) b2 ON b1.bug_id = b2.rand_id;
欠番が存在する場合は、アプリケーション側で対応するのが良さそうだと感じました。
例えばLaravelでは、以下のように記述することでランダムな値を取得できます。
LaravelModel::inRandomOrder()->first();
Collectionではrandom
メソッドが使えます。
ランダムに1件取得Collection::random();
以上です。
次回もお楽しみに!