はじめに
私はエンジニアになってから一貫してAWSでサーバーレス開発を行なってきています。 そのため、データベースといえばDynamoDBという世界で生きてきました。 これはいささか世間一般のバックエンドエンジニアの常識からは乖離しているものと思われます。
個人で開発していても、マルチテーブルなDynamoDBで設計をするとアプリケーション側でジョインするようなケースも多く、 これは単純にRDBを使っていればSQL一発でいけたのでは…というケースが非常に多かったです。 RDBの知見があればいいのになーと常々思っていました。
そこでRDBといえば…ということでミックさんの本を読んでみることにしました。
本書はミックさんのロードマップによれば一番最初の1冊です。 https://x.com/copinemickmack/status/1871863629706096770/photo/1
書籍名 | おうちで学べるデータベースのきほん 第2版 |
---|---|
著者名 | ミック、木村明治 |
出版年 | 2024年8月26日 |
ISBN | 9784798185354 |
書籍ページ | https://www.shoeisha.co.jp/book/detail/9784798185330 |
詳細は後述しますが、題名から受ける印象とは裏腹に、RDBを中心とした非常に広範な事柄に触れられていました。 ただただ入門をするというよりは、データベースの世界でより遠くまで歩を進めていくための最初の一歩として設計されているような印象を受けました。
印象に残った箇所
データベースに入門するにあたり、後半の専門的なトピックが特に興味深かったです。以下に特に印象に残った点をまとめます。
コストの話
繰り返しになりますが、私はエンジニアになって以来、一貫してAWSでサーバーレス開発を行ってきました。 そのため、コストに関しては基本的にAWSの説明を鵜呑みにしていました。
その内容としては、ざっくりいえば、よりマネージドなサービスを採用すればスケールアウトもスケールインも容易で当然コストも下がる、というものです。 POCが多い自分の職業経験からするとこれには完全に同意できるものでした。
しかし、規模感が大きくなるとオンプレとクラウド利用とで損益分岐点があるという認識を持っていました。
本書においては、以下のような点に触れられています:
- **TCO(総所有コスト)をイニシャルコスト(ライセンス費用など)とランニングコスト(サポート費用)**として捉えて、それぞれの取捨選択がありうること
- イニシャルコストに対するユーザーの反感が根強いので、サブスクリプションや従量制というモデルもクラウドを中心に提供されていること
また、それらを踏まえて、イニシャルコストの安さを過度に評価するバイアスが我々にはあるからTCOで考える癖をつける必要がある旨書かれていました。この視点は非常に重要だと感じました。
ACID特性について
本書の第7章「トランザクションと同時実行制御」において、トランザクションについて詳しく解説されています。 また、ACIDのDにあたるDurabilityについては第9章で触れられています。
私が親しんできたDynamoDBにおいては、一部トランザクションがサポートされているものの、あまり実用の機会は多くないように思います。 それよりも結果整合性という特性を踏まえて読み取り時にその部分をケアする、または、妥協するという設計がなされる傾向にあると感じます。
そういう意味でトランザクションをほとんど意識したことがない自分としては非常に新鮮に感じる内容でした。
ACIDのIの話
分離性の話は特に興味深かったです。
ANSIが定義する分離性の区分は以下の通りです:
- Read Uncommitted
- Read Committed
- Repeatable Read
- Serializable
トランザクション関連のデータ読み取りにまつわる不都合な事象が以下の通りです:
- Dirty Read
- Fuzzy Read(近年では、Non-repeatable Readの方が多いらしいので、以降はNon-repeatable Readと表記します)
- Phantom Read
それぞれの対応が以下の通りとなっています:
- Read Uncommitted(いずれもガードできない)
- Read Committed(Dirty Readはガード)
- Repeatable Read(Dirty Read、Non-repeatable Readはガード)
- Serializable(いずれもガード)
MySQL では分離レベルは、トランザクション(セッション)単位またはグローバル設定で変更可能なようです。
DynamoDBの世界では結果整合性または強い整合性をQueryやGetItemの際に選べるという世界なので、ぐっと見え方が違うなと感じました。
ACIDのDの話
クラッシュリカバリーについて以下のポイントで説明されていました:
- WAL(Write-Ahead Logging)
- データベースバッファ
- クラッシュリカバリ
不勉強ながらRDBの書き込みは全てディスクに同期的に書きこんでいると思っていたので、ログを介在させてディスクへの書き込みやロールフォワードが行われるということには驚きました。
また、バックアップについては、以下のようなポイントで説明されていました:
- ホットバックアップ/コールドバックアップ
- 論理バックアップ/物理バックアップ
- フルバックアップ/部分バックアップ
- 差分バックアップ / 増分バックアップ
データベースを関数として捉えるという視点
正規化もER図も「『テーブルが集合であること』と『テーブルが関数であること』を理解する」ことの補助的なツールである、というのが第8章の主題でした。
特に「テーブルは関数である」というところは目から鱗でした。 文中でも触れられていますが、関数というと一つの数式で表せるものというイメージがありましたが、数式としては不定の関数として捉えることができるという視点は新鮮でした。 ここを踏まえると、部分関数従属性および推移的関数従属性を廃する正規化というものの意味合いがスッキリ理解できました。
パフォーマンスの話
DynamoDBを扱っていると、QueryかGetItemに持ち込めればあまりパフォーマンスを気にする機会はないという認識でした。 そのため、性能というのは設計時のキー設計でおおかた決まるということだと考えていました。
一方で、RDBにおけるクエリは以下のような流れでデータアクセスがなされます:
- (クエリとは別のタイミングで)非同期で統計情報作成
- 構文のパース
- 統計情報を元に実行計画を作成
- 実行計画を評価
- データアクセス
クエリの最適化という点においては、DynamoDBよりもよっぽど手厚くマネージドな内容である点が意外でした。
また、最適化のためにインデックスが有効であり、そのインデックスがB-treeで構成されているという点はDynamoDBとも共通する部分があることに気づきました。
まとめ
DynamoDBしか実務経験がない私としては非常に学びの多い書籍でした。
RDBという名称から、単に「テーブル同士のリレーションを作れるテーブル」くらいの認識しか持っていませんでした。 実際は、本書で扱っているような広範な分野が存在しており、その全体像を把握することができました。特にACID特性やトランザクション、正規化の考え方など、理論的な背景を理解できたことは大きな収穫です。
今後はこのシリーズを数ヶ月かけて読み進めていきたいと思います。また、学んだ知識を実際の開発にどう活かしていけるか、DynamoDBとRDBのハイブリッド的な運用も含めて検討していきたいと思います。