lasciva blog

開発して得た知見やwebビジネスのストック

「失敗から学ぶ RDBの正しい歩き方」を読んだ

失敗から学ぶRDBの正しい歩き方 (Software Design plus)

失敗から学ぶRDBの正しい歩き方 (Software Design plus)

目的、モチベーション

めちゃくちゃ目的意識がある訳ではなかったが、最近DB関連の勉強あまりしてないので、面白そうだから読んで見るかぐらいの温度感で読んだ。
私自身は、普段MySQLを使っていて、アプリケーションエンジニアとしてテーブル設計、SQLチューニングをしている。
体系的に学んだという観点では、本でいうと過去に↓あたりを読んだことがあるぐらいのレベル感。

実践ハイパフォーマンスMySQL 第3版も読もうとしたが、辞書すぎて途中で挫折した。。

知らないことも多く、読んで良かったのでオススメ。

全体の感想

  • 全体的に、現場で起こりそうなアンチパターンを紹介して、その原因と対処法を書いてある形式で、話が入ってきやすかった。
  • SQLアンチパターン(過去に既読)と重複してる部分も少しはあるが、運用面も対象にしている点が特に異なり、学びが多かった。
  • DBの理解(特に運用面)が浅いことが認識できた。
  • PostgreSQLMySQLは結構違いがあって面白そうだと思った。
    • RDBMySQLしか使ったことないが、PostgreSQLはアグレッシブ目な機能とかもありそうな印象を受けた。

目次

概要

第2章 失われた事実

アンチパターン:レコードをむやみに更新すると、履歴データが失われる

  • 履歴データも保存することで解決するが、パフォーマンスとのトレードオフ
  • パフォーマンスを取るなら、他の手段でログを残すこと。

第3章 やり過ぎたJOIN

  • JOINのアルゴリズムをまず理解することが重要。
    • NLJ(MySQLはこれだけサポート)
    • Hash Join
    • Sort Merge Join
  • JOINはテーブル同士を掛け算するので、大きいテーブルをJOINするとコストが高い。
  • 更新頻度が低ければ、別テーブルを作成したり、Viewを活用する。

  • 参考: Where狙いのキー、order by狙いのキー

第4章 効かないINDEX

INDEXが効かないケース

  • 検索結果が多い、全体の件数が少ない
    • テーブルスキャンの方がコストが低いために、使われない。
    • 検索結果がテーブル全体の20%未満が目安
    • 数万〜数十万行程度に、テーブルが十分大きいこと
  • 条件にその列を使っていない
  • カーディナリティの低い列に対する検索
  • あいまいな検索
    • 部分一致でもINDEXを効かせたい場合は、Mroongaなどを使う
  • 統計情報と実際のテーブルで乖離がある場合

第5章 フラグの闇

第6章 ソートの依存

  • RDBは、そもそもは集合論のモデルなので、sortという概念がなく苦手な処理である。
  • INDEXを使って、ソート済みの結果を使うなどの工夫が必要。
  • OFFSETはソートした結果をfetchしてるので、ページングが奥になればなるほど高コスト。
    • idなどで、次ページを特定するようにして、OFFSETを避けるなど。
  • またはNoSQLを使う

第8章 JSONの甘い罠

  • デメリット
    • RDBのメリットであるはずの制約を与えられない
    • 検索、更新が困難
  • 使い道
    • サードパーティのレスポンスなど、key名等が変わる可能性があり、参照さえできればよいデータなど

第9章 強過ぎる制約

無闇に強すぎる制約はよくない。
ビジネスロジックの変更の度に変えないといけなくなったりするのはよくないので、 アプリケーション側の規約と、DB側の制約をバランスよく使い合わせるのが大事。

第10章 転んだ後のバックアップ

アンチパターン: リストアしてるが、復旧できない状態になっていること

  • バックアップの種類
    • 論理バックアップ
      • SQL等で保存して、DBそのものを再構築できるようにする方法。
      • 容量が大きくなってしまい、リストアとバックアップに時間がかかる。
      • バージョンアップ等にも対応できる。
    • 物理バックアップ
      • DBのデータのファイルを直接保存する方法。
      • サイズが小さく、時間も短い。
      • バージョンアップ等で使えなくなる可能性がある。
    • PITR
      • バックアップと、更新情報のログ(バイナリログ)が必要。
      • 最新の状態に戻せやすい
      • 上記より扱いが難しい。
  • バックアップ設計の観点
    • RPO( Recovery Point Objective )
    • RTO( Recovery Time Objective )
    • RLO( Recovery Level Objective )
  • 参考
  • 自動化すべき
    • 本番のDBをリストアして、ステージングで復旧して、シナリオテストを実行して、本番環境とステージングでの差分が発生していないかを確認

第11章 見られないエラーログ, 第12章 監視されないデータベース

  • ミドルウェア構築時の1プロセスとし、必ず設定して、可視化や通知を行うこと。
  • サービスの成長とともに変化するので、定期的に見直すこと。

第13章 知らないロック

RDBMSによって、全然挙動が異なるので、思い込みは厳禁。

第14章 ロックの功罪

トランザクション分離レベル

ダーティーリード ファジーリード ファントムリード ロストアップデート
read uncommitted 発生 発生 発生 発生
read committed 起きない 発生 発生 発生
repeatable read 起きない 起きない 発生 発生
serializable 起きない 起きない 起きない 起きない

第15章 簡単過ぎる不整合

  • 基本的には非正規化はダメ。
  • キャッシュを組み合わせてカバーする(キャッシュ乱用も良くない)。
  • JOINを減らしたければ、CHECK型やENUM型で正規化の階層を減らすことを検討する。

第16章 キャッシュ中毒

  • キャッシュは複雑度を上げる。
    • データがおかしいのか、キャッシュがおかしいのかなどの切り分けが大変。
    • 参照されたタイミングのキャッシュがどのデータなのか把握するのが困難。
    • パフォーマンス面であまり依存しすぎると、キャッシュが消えてしまったら大障害につながる。
  • キャッシュの種類
    • クエリキャッシュ
      • クエリの結果がキャッシュか否かの判別ができない
      • テーブル更新されるとクリアされる(更新頻度が高いとパフォーマンスが悪くなる)
      • 全く同じクエリでないとキャッシュされない(日時が絡んだりするとアウト)
    • マテリアライズド・ビューとサマリーテーブル
    • アプリケーション側でのキャッシュ

第17章 複雑なクエリ

テーブル設計が悪いか、(知識がなく)SQLの書き方が悪いを見極めること。

第18章 ノーチェンジ・コンフィグ

公式ドキュメントで何がコントロールできるかを知ること。

一度適切に設定したら、大体は使い回せるので、ソースコードをしっかりバージョン管理すること。
初心者で情報が多すぎる場合は、チェックツールがオススメ。

第19章 塩漬けのバージョン

  • メジャーアップデートの方法
  • 過剰に恐れず、旧バージョンに戻せるようにリハーサルしておき失敗できる状態にしておくこと。

失敗から学ぶRDBの正しい歩き方 (Software Design plus)

失敗から学ぶRDBの正しい歩き方 (Software Design plus)