RDB脳 って何
俗に「RDB脳」と呼ばれる現象の発生が、ソフトウェア開発者の中で知られています。
これは、リレーショナルDBを利用してきた技術者が、非リレーショナルなDBを使おうとした際に、以下の現象がみられるものです。
- 非リレーショナルなDBの仕様の理解に苦しむ。
- 非リレーショナルなDBを使いこなせず、十分な性能が出ない。
非リレーショナルなDBの登場について
歴史的にはリレーショナルDBの欠点を解決するために登場したのが、非リレーショナルなDBと考えていいと思います。リレーショナルDBの欠点は、具体的には以下ではないかと思います。
- プライマリキー
レコードを唯一に識別する仕組みとして使用されているがプライマリキーです。単純にユニークな値を持つ単独のIDとかで十分なのに、わざわざ複数のデータを使うのは不自然です。
リレーショナルDBが普及し始めた当時は、今と違ってまだストレージが高価だった時代ですので、ストレージの節約は重要でした。少しでもストレージを節約するために、データの一部をIDとして利用することで、記録に必要な容量を減らす仕組みがプライマリキーであると考えられます。IDだとユニークにするためには短くないはずですので、それさえも削減したいということでしょう。
(CassandraやDynamoDBのように非リレーショナルでありながらプライマリキーの概念があるDBも存在します) - Write on Schema
レコードを記録する前に、レコードのデータ構造であるスキーマを決定しておく必要があります。当然スキーマと異なるデータ構造は記録できませんので、データ構造の変更は容易にはできません。
またレコード間でスキーマを揃えなくてはならないので、実際にデータが保存されているのは一部のフィールドのみという無駄が発生する状況になることもあります。 - スケーリングへの対応能力
クラウドで処理能力を拡大/縮小する仕組みであるスケーリングへの対応が難しいようです。そのためクラウドベンダーの用意したクラウドネイティブなリレーショナルDBでない場合は、スケーリングへの対応はレプリカの設定程度に限定されます。
非リレーショナルなDBのプロダクト
Google Cloudだと以下が非リレーショナルなDBです。
- ドキュメント指向DB
- Firestore
- キー・バリュー型DB
- Bigtable
- Memorystore(Redis/Valkey/memcached どれもキー・バリュー型)
- Datastore(Firestoreの前身のいにしえのDBであり、すでに提供終了)
RDB脳を生み出す原因
RDB脳を生み出す原因となっているのは、リレーショナルDBと非リレーショナルDBの仕様や使い方の違いと思われます。具体的には以下が該当しそうです。
- SQL vs. NoSQL
リレーショナルDBは一般的にはSQLで利用されます。
それに対して非リレーショナルDBは、「Not only SQL」を略して「NoSQL」と表現されるように、SQLを使用しません。SQLライクな言語が用意されることもありますが(例:CassandraのCQL)、そもそも言語で操作が不可能なDBもあります。 - Write on Schema vs. Read on Schema
非リレーショナルDBがNoSQLである理由の1つです。
「Write on Schema」は、データの書き込み前にスキーマを決定しておく必要があることを表しています。リレーショナルDBで採用されています。
「Read on Schema」は、データの書き込み時にはスキーマを固定しておく必要はありません。かと言ってスキーマが存在しないのではなく、データを読み出すとスキーマが判明します。そのためデータごとにスキーマが異なる可能性があります。 - プライマリキー vs. ID/キー
リレーショナルDBで一般的に使われるSQLでは、レコードを一意に識別するために、レコード内の複数のデータを組み合わせてプライマリキーとして利用します。
非リレーショナルDBで用いられるIDまたはキーは、それだけでデータの記録場所を特定できます。 - 正規化 vs. 非正規化
リレーショナルDBの場合は通常、1つのデータは1つだけ保存されるようにデータ構造を最適化する正規化を行います。これによりデータの一貫性を保証します。
非リレーショナルDBでは、読み出し時のレスポンスを確保するためにあえて非正規化する場合があります。 - CURDの概念
非リレーショナルDBでは一般的に、CreateとUpdateの違いがありません。どちらも書き込みであり、新規追加か既存更新かは意識しません。 - 取得の概念
リレーショナルDBで一般的に使われるSQLには、検索と取得の区別がありません。データを取得するためには、検索します。レコードの識別がID/キーではなく、プライマリキーという複数のデータであることに起因しています。
非リレーショナルDBでの取得は、ID/キーを使用して一発で取得できます。そのため検索は別の機能です。またキー・バリュー型DBの場合は、検索が用意されていないこともあります。 - インデックスの扱い
リレーショナルDBでは検索の高速化のために任意で使用しますが、非リレーショナルDBでは単に検索するために予めインデックスを作っておく必要があることもあります。
事例
実際RDB脳でやらかしてしまったと思われる事例は、ネットでも見つかります。
Firestore → Cloud SpannerでDBコスト93%削減!無停止でやり切った 1 年間の全記録
どのような処理を行っているのか説明されていないので推測ですが、状況からRDB脳案件の可能性があります。DBマイグレーションしてますが、移行先がRDBのSpannerなので、RDB脳なら問題なく使えるのは当たり前です。
FirestoreはサーバレスなのでI/O数によって課金される仕様です。そのため無駄にI/Oを行う実装になっていると、この記事のような運用コストの問題が発生します。まずは無駄なI/Oを削減する必要があります。ロジックを見直すのが本来の解決方法ですが、MemorystoreやFirestore Data Bundlesでキャッシュするのも有効な解決手段となります。
あるいは本来Firestoreが向かない用途に使ってしまったケースかもしれません。
Spanner は本当に高い?思ったよりも低い Firestore との損益分岐点
上記の記事と同じ状況と思われます。無駄にI/O行う実装になっていないか疑問があり、結論の信憑性に大きな疑問があります。
非リレーショナルDB初心者にありがちな失敗談が語られていて、共感できます。
しかし非リレーショナルDBではテーブルにする必要がない点で、非リレーショナルDBでの実装が必ずこのようになるというわけではありません。結果整合性についての記述もそれを採用したDBではそのとおりですが、強整合性のDBではあてはまらないことに注意が必要です。
ある夏のFirestoreのこわい話
うっかりやらかしていたことに気付いて改善した例です。この例はSQLでも同じ問題が起きます。やらかしていることに気づきにくく、思わず同情してしまいました。
「DB = リレーショナルDB」は過去の話
RDB脳を回避する方法
リレーショナルDBに慣れた方が、新たに非リレーショナルDBを学ぼうとする場合、RDB脳に陥る可能性があります。まず非リレーショナルDBを学ぶ前に、リレーショナルDBの知識・経験をきれいに忘れてください。
...と言っても、現実はそんな都合よく忘れられるわけがないのが困ったところです。
私の場合はドキュメント指向DBから入ったという経緯もあり、私だけかもしれませんが、後から学んだリレーショナルDBが「ヘンテコな仕様」に見えました。具体的には以下が理解しがたかったと記憶しています。
- SQL → なんで言語にする? やるならGUIだろ。
- プライマリキー → なんでIDじゃないの?
- 取得がない → なんで検索(query)しかないの?
- Write on Schema → 実装は難しかしそうなので、仕方ないか。
- JOIN/MERGE → 意味不明。
RDB脳を回避するには、まずは非リレーショナルなDBについてそれが生まれた背景や、目指すところの違いを意識するのが早いのではないかと思います。そうすれば自ずと特徴や使いどころも理解できるのではないでしょうか。