失敗から学ぶRDBの正しい歩き方 (Software Design plus)
https://m.media-amazon.com/images/P/B07P8PMHLL.01._SCLZZZZZZZ_SX500_.jpg
目次を見る限りだと20章あり、1章ごとの内容が
アンチパターンの概要
会話での具体例(営業とエンジニアの乖離問題)
どこが問題だったのか
といったところを説明している。
第1章 データベースの大迷宮
table:RDBにおける制約
PK 重複とNULLがなく、そのテーブルで一意な行であることを確定させる
NOT NULL NULLがないことを確定させる
UNIQUE その値がテーブルで一意であることを確定させる
CHECK 指定した条件の値のみが保存されていることを確定させる
DEFAULT 値が指定されるないときに保存される値を決める。それにより初期値を確定させる
FK 別テーブルの主キーと参照整合性が保たれていることを確定させる
前の設計者の独自のルール設計になっている。
0:未削除
1:削除済み
2:管理者による強制削除
…
こういったものが変数フィールドの値として入ってても一目では分からない設計となっている。
第2章 失われた事実
後からデータを遡れるような設計にする。
しかし、レコードの保存料が増える&テーブルサイズが肥大化した際に検測速度が劣化してしまう。
解決策?として
マテリアライズド・ビューの利用
集計済み結果を作成したSummaryテーブルを作成する。
DBに履歴を持たせたくない人は、
遅延レプリケーションを使う
遅延したスレーブDBをつくること
アプリケーションログとしてElasticsearchなどの分析ツールに保存する
大前提として、履歴データはRDBでは想定していない。しかし、実務では使うケースが非常に多い。
第3章 やりすぎたJOIN
JOINは必要最低限にする
だからといって、使うのをしぶりすぎるとN+1問題の温床になったり、無駄なクエリを発行することになる。
NLJ
Hash Join
Sort Merge Join
第4章 効かないINDEX
BTree INDEX
1,000以下のテーブルなら、テーブルスキャン(フルスキャン)のほうが高速になる。しかし、10,000行となるとインデックス参照のほうが早くなる。
第5章 フラグの闇
delete_flagといった列名をつくり、01だけのもので表現すると、カーディナリティが低くなる。また、UNIQUE制約が使えない列も出てくる。そして、どの状態が最新のものなのかをタイムスタンプと合わさって、判断しなければならない。
解決策として、
delete_usersテーブルを作成する。
トリガーを使う
Viewを使う
がある。
PostgreSQL→マテリアライズド・ビュー
MySQL→サマリーテーブル
delete_flagはいわゆる「状態」をもたせている。事実だけを残すように。
ただ、「状態」をもたせるのも一概に悪いわけではない。しかし、後々の変更がきつくなったりするので、無難にテーブル分けるのがいいらしい。そして、「状態」を解決する銀の弾丸は存在しない。
このアンチパターンはじわじわくる問題なので、今後大きな問題にならないように細心の注意を払う必要がある。
第6章 ソートの依存
ORDER BYは割と重い処理
エグゼキュータによる評価順序
FROM
ON
JOIN
WHERE
GROUP BY
HAVING
SELECT
DISTINCT
ORDER BY
LIMIT
いきなりORDER BYをするのは、アホ?
第7章 隠された状態
EAV
jsonで代替可
Polymorphic Associations
子テーブルが複数の親テーブルを持つような設計
第8章 jsonの甘い罠
EAVからjsonデータに変更するときの注意点
正規化することはできないか
jsonに対して頻繁に更新を行いたいか
検索条件としてjson内の属性が固定できない場合
1つでも該当する場合はjsonデータ型を採用すべきでない
↑大体は当てはまるので、最後の切り札しての認識で。
第9章 強すぎる制約
デッドロック
排他ロック
ギャップロック
早すぎる最適化
制約なし
弱い制約(FK, UNIQUE, NOT NULL)
強い制約(CHECK, EXCLUDE)
強すぎる制約(特定の文字列しかドメインのemailしか入らない)
第10章 転んだ後のバックアップ
論理バックアップ
物理バックアップ
PITR
バックアップをする際に、RPO, RTO, RLOについて考えなければならない。
第11章 見られないエラーログ
エラーログは見ろ。エラーログは見ろ。エラーログは見ろ。
MySQL
ログファイルの種類は主に4つ
General Query Log
接続情報や実行したクエリ情報に関する操作の情報
実行したクエリすべてが記録されているので、ファイルサイズが大きくなりやすい。デフォルトではFalse
Slow Query Log
クエリの処理にかかった時間
Error Log
Error
Warning
Note←意味はNotice(注意)という意味
Debug Log
開発者用のトレースログ
PostgreSQL
割れ窓理論にならないように注意しましょう…
第12章 監視されないデータベース
死活監視
チェック監視
メトリックス監視
何をモニタリングするべきか?
OS側
ディスクI/O
ネットワークトラフィック
CPU利用率
メモリ利用率
RDBMS側
SELECT/INSERT/UPDATE/DELETEなどの実行料
実際に読み込まれているレコードの量
インデックスヒット率
デッドロックの可否テンポラリファイルの作成の有無
ロックの量と時間
MySQLのモニタリング
PMP
Zabbix
Cacti
PostgreSQLのモニタリング
ph_monz
品質の可視化と改善は両論
ダイエットは体重計に乗らないと知ることができないし、体重計に乗ったからといって痩せるわけではない。
第13章 知らないロック
ロックにはレベルと粒度が存在する。
レベル
排他ロック
共有ロック
粒度
表ロック
行ロック
トランザクションとデッドロック
デッドロックとは…?(具体例)
漫画が1,2巻ある。そして、1巻を持ってる友人Aと2巻を持ってる友人Bがいる。
友人Aは2巻の返却待ちをしている。(2巻借りたら、1巻返す)
友人Bは1巻の返却待ちをしている。(1巻借りたら、2巻返す)
お互いお互いの本の返却待ちで、どちらも読み始められない。
この状態のことをデッドロックという。
MySQL
ギャップロック
ネクストキーロック
RDBMSごとにロックの振る舞いが違うということを自覚し、扱いには気をつける。
第14章 ロックの功罪
ロックは並列処理からデータを守っている。しかし、すべてを直列処理にすると、処理待ちが高頻度で発生してしまいサービスが遅くなることが予想される。
table:ACID
Atomicity トランザクション内の操作がすべて実行されるか、されないかを保証する。
Consistency 指定された状態に対して整合性がある、一貫性があることを保証する。
Isolation 実行中のトランザクションがほかのトランザクションに影響を与えないことを保証する。
Durability 一度コミットされたトランザクションは、何があっても残されることを保証する。
Isolationを完全に担保しようとすると、直列処理で1件ずつ処理する必要がある。
これはIsolationの制限を緩めているからである。この制限のレベルを定義しているのが、トランザクション分離レベルである。
1. read uncommitted
2. read committed
3. repeatable read
4. serializable
table:トランザクション分離レベル
ダーティリード ファジーリード ファントムリード ロストアップデート
read uncommitted 発生 発生 発生 発生
read committed 起きない 発生 発生 発生
repeatable read 起きない 起きない 発生 発生
serializable 起きない 起きない 起きない 起きない
第15章 簡単すぎる不整合
RDBは安易に非正規化を行ってはいけない。むしろ正規化から始まり、正規化で終わるのが良いとされている。
このことを念頭に置き、RDBMSの論理設計を行うようにしよう。
第16章 キャッシュ中毒
キャッシュは麻薬
うまく使いこなせば、味方になる。
キャッシュの種類
クエリキャッシュ
実行されたSQLが同じなら結果も同じになるはず
デメリットも!
実行されたクエリの結果が、キャッシュなのか最新情報なのかわからない
テーブルが更新されるとキャッシュとして不適切なため、クエリキャッシュはクリアされる
まったく同じクエリでなければキャッシュされない
マテリアライズド・ビューとサマリーテーブル
第17章 複雑なクエリ
前回書いたDBAの人の意図と背景を読み解く。
複雑なクエリはゴリ押しで解決するのではなく、モダンなやり方でなるべく解決する。(モダンな書き方で解決する。)
第18章 ノーチェンジ・コンフィグ
コンフィグの役割を知る。
データベース担当者でもコンフィグを知らないケースが多いため、気をつける。
MySQLの挙動では、以下のURLで参照するとよい。
第19章 塩漬けのバージョン
キョジオーン
バージョンアップをしないと、後々大変なことになる。
以下の工数をある程度防ぐことで、解決するケースが多くなる。
1. バージョンアップ方法の決定
2. コンフィグの確認
3. リハーサル
4. バージョンアップ作業
第20章 フレームワーク依存症
マジックビーンズ
フレームワーク特有の能力のせいで、無駄なカラムやテーブルを生成してしまう恐れがある。