RDB と NoSQL — 問い合わせの形を、いつ決めるか
性能の比較ではなく「アクセスパターンがもう固まっているか、まだ動くか」で選ぶ。後から取り方を増やしたくなったとき、何が起きるかの違い。
先に読んでおくとよい記事
この記事の進み方
What — 同じ要件を、どう取りにいくか
「あるユーザーの注文一覧を、新しい順に20件」。ありふれた要件です。3つの設計で、それぞれ何をすることになるのかを見てください。
データを正しく置き、問い合わせは後から組む
SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 20- 設計の起点
- データの構造(正規化)
- 取り方を増やす
- インデックスを1本足す
- 結合
- JOIN でその場で組める
- 整合性
- トランザクションで保てる
- スケール
- まず縦。横は分割の設計が要る
- –取り方を決めずに始められる。要件が動く段階で強い
- –どう取るかはプランナが決める。人が指定するのは索引まで
- –遅いときは実行計画を読んで原因を特定できる
速さの比較ではない。見るべきは「設計の起点」と「取り方を増やしたときに何が起きるか」の2行。
- アクセスパターン
- アプリがデータをどう取りにいくかの一覧。「ユーザーIDで注文を新しい順に」のような単位で数える。
- パーティションキー
- データをどのサーバーに置くかを決める値。ここで割れることが、横に伸びる条件になる。
- GSI
- Global Secondary Index。別のキーで引くための索引。元のデータとは別に、索引用のコピーが作られる。
- 走査
- キーで絞り込めず、全件を読んで条件に合うものを拾う動き。コストが件数に比例する。
取り方が1つ増えたとき、何が起きるか
冒頭の事故は、この一手で決まりました。
- 1属性はあるが、キーではないデータは入っている。引けないだけ軽い
- 2走査で暫定対応する動く。ただしコストが件数に比例する重い
- 3GSI を足す別のキーで引くための索引を作る中
- 4既存データを埋め直す索引ができるまで待つ重い
- 5次の要件が来るここまでをもう一度やる重い
RDB なら、この工程はほぼ「インデックスを1本足す」で終わる。索引を足しても既存のクエリは動き続け、データの持ち方も変わらない。
どれも解決策ではある。問題は、要件が増えるたびにこの工程を繰り返すことになる点。
キーバリュー型のデータベースで「1件取るコストがデータ量に依存しない」のは、なぜですか?
Why — 「いつ形を決めるか」の選択
RDB は「データを事実として正しく1か所に置き、問い合わせは後から自由に組む」という設計です。正規化で重複を排し、必要になった取り方にはインデックスを足す。どう取りにいくかはクエリプランナが決めます。
この設計は、取り方が決まっていない段階でも始められることに価値があります。何を作るかがまだ動いているとき、これは大きい。
キーバリュー型はその逆です。取り方を先に決め、その形でデータを並べておく。並べてあるから探さずに済み、キーで割れているから横に伸ばせます。
つまりこの選択は、性能の優劣ではありません。
問い合わせの形を、いつ決めるか。 RDB は後で決める。キーバリューは先に決める。先に決めたぶんだけ速く、後から変えにくい。
決まっているなら、先に決めてよい
このサイト自身が、この判断を一度ひっくり返しています。
当初は PostgreSQL で確定していました。主な理由は、検討していた認証ライブラリが SQL と MongoDB にしか対応していなかったからです。ところが認証を Cognito に変えた時点で、その制約が消えました。根拠が消えた結論を残すわけにいかないので、再検証しました。
見直すと、このサイトのアクセスはすべて「そのユーザーの何か」でした。読了、お気に入り、演習の回答、購読の状態。全部ユーザー ID で綺麗に割れます。要復習の一覧だけが別の取り方でしたが、これは索引1本で足りました。
つまり、アクセスパターンがもう動かないと判断できた。だから先に決める側を選べました。冒頭の在庫管理との違いは、扱う技術ではなく、そこの確信度です。
「DB の値段」と「そこへ到達する値段」
再検証のとき、もう1つ見落としが見つかりました。
RDS の構成を「月 $23」と見積もっていたのですが、これはマネージド DB の料金だけを数えた金額でした。RDS は VPC の中にあるので、そこへ繋ぐ Lambda も VPC に入る必要があります。そして VPC の中の Lambda は、既定のままでは外部のインターネットに出られません。決済 API を呼ぶには NAT Gateway が要り、それが月 $45 でした。
実コストは $23 ではなく $68。差は月 $66、年間で約12万円です。
次のうち、キーバリュー型を選ぶ根拠として最も強いものはどれですか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
この条件で、どのデータストアを選びますか?
- 社内向けの実験的なプロダクト。最初の利用者は20人ほど
- 何を作るかはまだ動いている。仕様は週単位で変わる
- Lambda で動かす前提。常時起動のサーバーは持たない
- 個人情報を扱うので、監査のために誰が何を見たかを後から集計したい
- 半年後に社内公開し、数百人規模になる可能性がある
- · 取り方がこれから増えたときに、何をすることになるか
- · 常時起動しない実行環境から、どう繋ぐか
- · 利用者20人の段階で、月にいくらかかるか
「NoSQL のほうが速いらしいので使いたい」と言うメンバーに、何を確認すべきか説明してください
- 相手は新しい技術を試したいという動機もある
- 頭ごなしに否定したくない。実際、条件が合えば良い選択になる
- この会話のあと、相手が自分で判断できるようにしたい
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。