ちょうどいい正規化の話 by @nakunaru
最低限のライン
- 不整合を起こさない
- データを失わない
ダブらせない
→更新漏れ、複数行(リソースをたくさん使う)
→1 fact 1 place
余談
1 fact q place は結構難しい。情報ってなんだ??
データと情報の違い
データ: 値そのもの。 3520
情報: データを分類・整理して意味を持ちせたもの。商品番号800番の価格3520
「商品の価格」「販売時の価格」などの「〇〇の□□」という見方でデータを見ると情報が浮かび上がる
同じ「価格」でも、「商品価格」と「購入価格(割引があるかも??)」なら共通化してはいけないよね??
ロストしない
DELETEしたときに想定外の情報が消えないようにする
買い物かごから商品を消す→元の商品データが消えるwwwww(笑えねえ)事態にならないために
そのデータを消すことで何が消えるのか??
主キーに仕事させる
受注番号と注文者番号「あれ、注文者番号があれば受注番号がなくても特定できるよ……」だめですねえ
(間接関数従属)
↓
正規化しましょう
つまり、正規化の視点のお話!!
A. 定価・割引率・結果を明細テーブルに履歴として持っておくと、まあデータが無くなることはなくて安全。
事実をぶっこんでおけば即死は免れる。
Q. 1 fact 1 place
A. 昔の職場のエライ人が言ってた。
Q. 正規化ってどこまであるの?
A. 第6くらいまである。第三+ボイスコッド正規化まですればいい。
申込におけるDB設計の失敗とたられば by @ngmt83
推し本
- らくらくERレッスン
- SQLアンチパターン
- そーだい本
10社の口コミと最安値がすぐわかる
- 入力項目が多い
- 入力に悩むことが多い
- 引っ越し一括見積りサイトに似ている
引っ越しサイトを例に挙げる
- 概要を入力
- 荷物について
- 個人情報
- (簡単なアンケート)
「どのステップでどの項目を入力するかは変わるかも」
……とりあえず、申し込みテーブルに1.〜4.の全ての情報を突っ込む設計
利 変更を行いやすい
不利 NULL入り放題、正規化ナニソレ、バリデーションは全てアプリで
途中で離脱したユーザーのために個人情報を先に入れよう。んで、途中のユーザーは途中のステップから入力したい。
→ステップという定義が乱れる
アンケートは荷物と一緒でいいな。
→ステップ合併
正規化しなかったのはまあよかったのか……??
「1問1問のフォームを同時並行で試したい」
ステップを各項目で……。
最初に正規化していたら相次ぐ変更で死んでいたな。。
1テーブル全ツッコミはまだマシだった。
だがしかし、リファクタリングする前提で工数確保したいですね、、難しいけど、、
「電話番号があればメールいらないかも」バリデーションんんん??
<= To Be Continued…
↑
これは相当やばいらしい(あまりピンとこなかった)
申し込みのDB設計は変わりやすい!!
- ユーザーの入り口で重要
- 繰り返し行うものではないから
- 初期段階のデータの不整合はよろしくない
データベース設計ミスるとロジックが死ぬ。。
雑談
アンケートも変わりやすいよね。
「〇〇年の結果テーブル」みたいな切り離せるけど、申込みはその後も使うから難しいよね
「RDBにしない選択肢」 jsonもアリ??
条件とか色々出てくるときついよね
ジーエーのデータ??というのがあるらしい(途中離脱の話)これぐぐっても出てこなかったんだが。。
アプリ側の話らしい??
(追記)グーグルアナリティクスっぽい
NULL嫌いのUPDATEしないDB設計 by @sinsoku_listy
nullとは
- 四則演算できん(すべてをnullにする)
- 比較できん(すべてをry)null == null もnull
- 集合関数で無視される
- 平均とか取ろうとするとないことにされる
- 並びかえがヤバイ
- そういえば、nullのせいでランキングの並べ替えできんかったな(Firestoreだけど)
- 3値論理 true, false, nullというbooleanになりうる
nullの侵入を防ぐ
- Railsのバリデーションで防ぐ
- required:true(勝手についてる), presense: true
- しかしすり抜けうる。バッチ処理とか
- not null制約(migration)
- DB側でエラーを出してくれるよ!
具体例
記事の下書き・公開・非公開
公開→公開者・公開日時 published_at(nullを許可)
バリデーション複雑になるし認可が面倒
fat controller updateはデッドロックの危険性がある
テーブルを分ける
article_publications, article_archivesとかで別にする
モデルも分ける(関連するpublicationモデルがあるかどうかで判定する)
コントローラも公開アクションをcreateにできる!
パフォーマンスは悪くなってからstatusを作る
ActiveRecord6.0
where.missing(:author)
- 論理削除に便利
- gem activerecord-missingも使える
check_constraint
Q. 記事の削除はどうするの?
A. KPI的にアーカイブにした方がいい。論理削除
Q. パフォーマンスが悪くなったらryのstatus変更はどうする?
A. article.publication
のafter_commit
でコールバック
保存した後にarticleのstatusを変える
管理者の許可〜とか、ちょっと遅れてもいいなら非同期処理にする
Q. 削除フラグは別のストレージに入れて消すのはどう?
A. user_archiveテーブルとかにjsonでカラムを残して本物は消す
read_onlyならjsonはアリ
Q. mysql, ポスグレとかjsonにindexは貼れるの? db2は行ける
A. generated column(生成カラム)で貼れる??
Q. 公開→非公開→公開のパターン
A. 公開と非公開はhas_many 非公開を消すことで公開状態にする設計
結局は要件次第
いつからいつまで公開、いつからいつまで非公開、とかいうデータが必要な場合も……(頭わやになりそう)