世界を動かす技術を、日本語で。

自分だけのデータベースを構築する

概要

  • データベース をゼロから構築する方法の解説
  • ファイルベース のシンプルなKey-Valueストアから始める流れ
  • 更新・削除の非効率性 とその対策としての「追記専用ファイル」戦略
  • インデックス導入 による検索高速化とメモリ・パフォーマンスのトレードオフ
  • ソート済みデータ構造 と耐障害性のための仕組みを紹介

Key-Valueデータベースの自作入門

  • Key-Valueデータベース は、JavaScriptのオブジェクトのように キー で値を保存・取得する仕組み
  • データの 永続化効率的な検索 が主な課題
  • 最も単純な方法は ファイル を使い、キーと値のペアを順次保存する方式

ファイルベースKey-Valueストアの基本操作

  • データの保存:db set 1 "Lorem ipsum" のようにファイルへ追記
  • データの検索:ファイル内の全ペアを 逐次検索
  • データの更新・削除:対象レコードを見つけて その場で書き換え・削除

問題点と改善策

  • 更新・削除時 に後続データの移動が発生し、 大規模化で非効率
  • 追記専用(Append-Only)方式へ移行し、 既存データは不変 とする
    • 更新や削除は 新たなレコード や「削除マーク(tombstone)」を末尾に追記
    • これにより、 データ移動のコスト削減

ファイル肥大化とコンパクション

  • 追記専用 方式では、不要なデータや削除済みデータも残り、 ファイルサイズが無限に増加
  • 一定サイズで セグメント(分割ファイル) を作成し、新規データは新セグメントへ
  • 古いセグメント は「コンパクション(圧縮)」で 有効なレコードのみ残して縮小
  • セグメントの 統合 も可能で、ストレージの効率化を実現

検索高速化のためのインデックス

  • ファイル全体を 逐次検索 するのは非効率
  • インメモリのハッシュテーブル などをインデックスとして利用し、 キーとファイル内オフセット を管理
    • キー検索時はインデックスからオフセットを引き、 直接ファイルを参照
  • セグメントごとに インデックス が必要
  • インデックスの更新は 書き込み速度低下 のトレードオフ

インメモリとオンディスクの違い

  • インメモリ は高速だがプログラム終了でデータ消失
  • オンディスク は永続化できるが、 アクセス速度は低下
  • インデックスは メモリ使用量検索速度 のバランスが重要

ソート済みデータ構造とスパースインデックス

  • ソート済み データにより、範囲検索やスパースインデックス(間引きインデックス)が可能
  • ソートされていれば、一部のキーのみインデックス化しても 効率的な探索 が可能
  • インデックス密度 を調整することで、 メモリ消費と検索速度 のトレードオフが可能

ソートと永続性の両立

  • データを 常にソート するのはディスク上では非効率
  • 解決策: インメモリでソート済みリスト に追加し、一定サイズで ソート済みファイル としてディスクへ書き出し
    • インメモリリストには バランス木やスキップリスト などを利用
    • 書き出し時に インデックスも生成
  • インメモリリストは クラッシュ時に消失 するため、追加ごとに 追記専用ログ へ保存し耐障害性を確保

まとめ:自作Key-Valueデータベースの流れ

  • 新規データ はインメモリのソート済みリストへ追加、同時にログファイルへ追記
  • リストが大きくなったら ソート済みファイル としてディスクへフラッシュし、インデックスを作成
  • 検索時はまずインメモリリスト、次にインデックスを使ってディスクファイルを参照
  • ディスク上のファイルは 不変(immutable) とし、更新・削除は新規レコード追記で対応
  • 定期的な コンパクション で不要データを除去し、ファイルサイズを抑制

このようにして、 シンプルかつ効率的なKey-Valueデータベース を自作可能。実際の商用DB(例: LevelDB, RocksDB, Redisなど)も、この基本構造を発展させている。

Hackerたちの意見

OPのいくつかの記事を見てみたんだけど、デザインとアニメーションがめっちゃ綺麗だね!素晴らしい!

この投稿のデザインと例が大好き。読みやすいし、こういうエクササイズは楽しそうだね。何かをゼロから始めるって、実際にどれだけ知ってるかの試験みたいだ。

ちょっとした批判として、ロレム・イプサムの例を使うのはあまり好きじゃないかな。読む気が失せちゃうことが多いし、リアルなデータが見たい。まあ、それを除けば、すごくいい投稿だよ。

最初は「自分でデータベース作るな、KVデータベースも使うな、SQLを使え」って思ったんだけど、自分でDBを設計したりKVデータベースを使ったりしたのは、SQLを避けたかったからなんだよね…でも結局、SQLを再発明しちゃってたって気づいた。いい教訓になったかも。

データベースを作るための無料のオンラインブックもおすすめだよ。https://build-your-own.org/database/

もうすでに抱きしめられすぎて死んじゃったみたいだね。

もっと速いデータベースが必要だね。

著者が見てたら、サイトにRSSフィードを追加してくれない?Feedlyに追加したいんだ。

この「ファーストプリンシプルズ」のアプローチでトピックを説明するのが大好き!これをじっくり見ていくと、どの問題を解決する必要があるのか、そしてそれによってどんな新しい問題が出てくるのかが理解できて、最終的には満足できる解決策にたどり着けるんだよね。

「実践におけるソート」セクションの最初の例、壊れてるっぽい。テキストではリストをメモリ内でソートしてからディスクに書き込むように見えるけど、実際にはディスクに書き込むときにリストがソートされてないんだよね。追記:要約セクションのフラッシュの例(2つ目)も同じことやってる。テキストではレコードはソートされた順でファイルに書き込まれるはずって言ってるのに。

ここ4週間くらい、トリプルストアを書いてたんだ!もうちょっと早く出てくれたらよかったのに、理解するのに時間がかかったいくつかの洞察があるんだよね :)

インタラクティブでいいけど、これって『データ集約型アプリケーションの設計』からそのまま持ってきた感じ。ここにあるコンテンツは、まさに第3章のインタラクティブ版なんだよね。もうちょっとクレジットをあげた方がいいんじゃない?

すごく面白い!開発者の活動を、各開発者がキーでコミットが値の時系列キー・バリューシステムとしてモデル化してるんだ。同じ問題に直面したよ:ログがすぐに増えるし、インデックスが重くなるし、範囲クエリが遅くなる。セグメントを圧縮するとき、何を捨てるかどうやって決めるの?新鮮さと保持のバランスを取るのが難しいよね。