Open6
失敗から学ぶRDBの正しい歩き方
- テーブルやレコードの中身がわかる適切な中身をつける
- 外部キー製薬やCHECK制約を利用してデータを適切に防ぐ
- リレーショナルモデルに基づいた設計を心がける
CHECK制約便利そうだけどバージョンの関係で使用できない
- 値が変更になる場合は履歴テーブルを作成する
マテリアライズド・ビューとは何か
履歴分だけパフォーマンスが低下するため、遅延レプリケーションやElasticsearchなどの分析ツールの使用を検討する
JOINには3つのアルゴリズムが存在する
JOINの改善としては、JOIN対象テーブルの整理やINDEXの利用、Viewの活用が考えられる
RDBMSがINDEXを使用しないケースは次の通り
- 検索結果が多い、全体の件数が少ない
INDEXを利用するためには次の2つの条件が必要
①検索結果がテーブル全体の20%未満
②検索対象のテーブルが十分に大きい - 条件にその列を使っていない
条件のカラムに数式を用いたり、関数を使用する場合 - カーディナリティの低い列に対する検索
カーディナリティ:「列に格納されるデータの値にどのくらいの種類があるのか?」 - あいまいな検索
LIKE検索:後方一致と部分一致では使用されない - 統計情報と実際のテーブルで乖離がある場合
削除フラグは次の問題を含んでいる
- クエリの複雑化(SELECTする際にJOINやWHEREをつける必要がある)
- UNIIQUE制約が使えない
データの重複が防げない
該当列に対して外部キー制約を利用できない
外部キー制約を利用できないことでデータの関連性を担保できない - カーディナリティが低くなる
解決策
トリガーを利用して削除済みテーブルを作成する
Viewを活用する
まず状態を持たせるべきか考える、次の点について考える
- 対象のテーブルが小さく、INDEXが不要
- そのテーブルが関連するテーブルの親になることがなく、データを取得する際に頻繁にJOINの対象になることがない
- UNIQUE制約が不要で、外部キーでデータの整合性を担保する必要がない
削除フラグを利用したくなるケース
- エンドユーザから見えなくしたいが、データは消したくない
- 削除したデータを検索したい
- データを消さずにログに残したい
- 操作を誤ってもなかったことにしたい
- 削除してもすぐに元に戻したい
リレーショナルモデルの世界にはソートがない
〜句 | 内容 |
---|---|
from | テーブル指定 |
on | カラム指定 |
join | テーブルの結合 |
where | 条件指定 |
group by | グループ化 |
sum,avgなど | 関数 |
having | 集計後の絞り込み |
select, distinct | 検索 |
order by | 並べ替え |
limit | 取得件数の指定 |
全てのデータを取り出してからORDER BYで並べ替え、最後にLIMITで必要なデータを切り分ける
データを取り出してからバラバラのデータを並び替えるため、ソートは高コストな処理ですし、
実際のデータを大きくなればなるほど、さらに重い処理になる。
解決策
1.WHERE句狙いのINDEX
WHERE句を利用してデータを絞り込んでからソートする
2.ORDER BY句狙いのINDEX
1の場合はカーディナリティが少ない場合はINDEXが適用されない場合がある
その他アプリ側でソート、結果をキャッシュする、NoSQLの利用が考えられる
第7章隠された状態
私も「失敗から学ぶRDBの正しい歩き方」をきっかけに、最近RDBのテーブル設計について学んでいます。とても参考になりました!
「失われた事実」「隠された状態」「フラグの闇」の解決案をあれこれ考えて記事にしてみました。
もしよかったら、いいね、コメント、ツッコミをもらえると嬉しいです!