簡易DBをフルスクラッチで実装して得た学び
☀️ はじめに
最近 「Database Design and Implementation」 という技術書を読みました。
本書は、一般的なDBMSについての設計パターンを概説しつつ、その一つのパターンをJavaで実装するというものです。
しかし、ただJavaのサンプルをそのまま動かすのでは味気ないので、今回は Go で書き直しています。
実装する機能はごくシンプルに絞っていますが、実際に自作することで「DBMSが内部で何をしているのか」が肌感覚でわかり、非常に勉強になりました。(まだ一部実装しきれていない部分はありますが...)
📝 実装した内容
この書籍では、DBMSの設計における複数の実装パターンを解説したうえで、そのうちの1つを実際に作るという構成になっています。おかげで、シンプルなDB機能を一通り体験しながら理解を深めることができました。今回実装した機能の一部を挙げると、次のとおりです。
- ストレージ層: ファイルにデータを永続化(バイナリ形式)
-
クエリ実行: 簡単な
SELECT / INSERT / UPDATE / DELETE
をパースして実行 - ログ・リカバリ: トランザクションログを記録し、クラッシュ時にリカバリできるように
- トランザクション: 最低限の同時実行制御
- クエリプランナー: (最適化は全くできていませんが)クエリ計画の基礎のみ
原著にはテストケースがあまり多くなかったため、自分のGo実装では適宜テストを追加し、動作を一つずつ確認しながら進めました。
✏️ 実際にやってみて感じた学び
1. DBMSが何をやっているかを肌で感じられる
SQL文が内部で「パース → 実行計画 → 実行」の流れを辿ることは頭では知っていたものの、実際にコードを書くことで
- どうやってデータをファイルに永続化するのか
- クエリ対象のデータをどのようにスキャンしていくのか
- システムが落ちたとき、ログをもとにどうリカバリするのか
などの「生の実装」を体験できます。特に「データの永続化」部分はレコードをどのようにファイルへ書き込み・読み取るかを理解しつつ実装する必要があり、想像以上に多くの工夫や手間が必要だと実感しました。
2. 普段使っている DB のドキュメントを理解しやすくなる
私は普段の業務で Google Cloud Spanner を利用しています。今回実装した簡易DBとは比べ物にならないくらい高度な機能を持つ Spanner ですが、本書を読んだおかげで
- 関連データを物理的に近くに配置してパフォーマンスを向上させるインターリーブ
- 同時書き込みを管理するマルチバージョン同時実行制御(MVCC)
などの機能についての理解度が上がりました。
もちろんこれらの機能について自分で実装はしていないのですが、関連するトピックについては本書で理解を深められていたこと、そしてそれに対する様々な設計パターンを学んでいたおかげだと思っています。
3. DBMS の偉大さの再認識
今回の本当に簡易なDBMS実装ですら、
- ファイルから “はみ出す” データをどう扱うか
- デッドロックを解消する仕組みをどう設計するか
- クエリ計画をどの段階でどこまで最適化するか
など考慮すべき事項が山ほどありました。しかし、世の中に名前の通っているDBは、これらをさらに巨大な規模で高度に実装しているわけですから、その凄まじさを改めて思い知らされました。さらに、内部実装をそこまで知らずとも使えてしまうこれらのDBのAPIはよく設計されているのだなとも感じました。
⭐ おわりに
「Database Design and Implementation」をベースに簡易DBMSを作ってみた結果、DBMSの仕組みを“体験”として学べたのは大きな収穫でした。
- クエリ実行の裏側がなんとなく見えるようになった
- DBMSの設計パターンとそれぞれのトレードオフを学べた
- 普段使っている高度なDBへの理解度も上がった
DBMSとしてそれっぽく動くまでかなり時間がかかりましたが、非常に色々な学びがありました。
まだ実装できていない機能もあるので引き続き実装を進めていくつもりです。
今後も「普段はブラックボックス化して扱っているシステム」について解像度を上げるべく、インプットを続けていきたいと思います。
Discussion