コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
データベースとは
同時に登録した 2 人のうち、片方が消える
問い合わせの内容を JSON ファイルに追記するだけの小さなツールを考えます。ファイルを読み、配列の末尾に 1 件足し、書き戻す。数十件のうちは何の問題も起きません。
壊れるのは、2 件が同時に届いたときです。ほぼ同じ瞬間に読むと、どちらも「9 件入った配列」を手にします。片方が 10 件にして書き、もう片方も 10 件にして書く。あとから書いたほうが勝ち、先に足された 1 件は跡形もなく消えます。エラーは出ません。ログにも残りません。気づくのは、送ったはずの人から催促が来たときです。
JavaScript
const list = JSON.parse(fs.readFileSync("inquiries.json"));
list.push(item);
fs.writeFileSync("inquiries.json", JSON.stringify(list));書き込みの途中でプロセスが落ちれば、閉じ括弧のない半端なファイルが残ります。次の読み込みは丸ごと失敗し、過去の全件がまとめて読めなくなります。
探すたびに、全部読み直している
件数が増えると別の問題が出ます。1 件を取り出すのに、毎回ファイル全体をメモリに広げて先頭から比べる。10 万件なら 10 万回の比較です。しかも「新しい順に 20 件」が欲しいだけでも、全件を読んでから並べ替えることになります。
同じ人が二重に登録されていないかを保証する手段もありません。書く側のコードが毎回正しく確認するしかなく、確認を 1 か所書き忘れれば、そこから重複が入り込みます。
バックアップも難しくなります。コピーしている最中に誰かが書き込めば、前半と後半で状態の食い違うファイルができあがります。書き込みを止めてからコピーすれば確実ですが、24 時間動くサービスでは、その数分が取れません。
DBMS は、この後始末を全部引き受けている
データベースとは、複数のプログラムから共有して使えるように構造化して保存されたデータの集まりで、それを管理するソフトウェアを DBMS と呼びます。MySQL や PostgreSQL、SQLite などが該当します。DBMS が肩代わりしているのは、次のような仕事です。
- 同時実行の調停 — 誰がどの行に触っているかを管理し、同時に書いても片方が消えないようにする
- 索引による検索 — 値の順に並べた索引を別に持ち、全件を読まずに目的の行へ辿り着く
- 制約 — 「この列は重複しない」「この値は必ず存在する相手を指す」を DB の側で拒否する
- 一括りの処理 — 複数の変更をまとめて 1 単位として扱い、途中で失敗したら全部なかったことにする
- 障害からの復帰 — 変更を先にログへ書いておき、電源が落ちても直前の状態まで戻せる
ロックと先行ログと索引と制約と復旧処理を自前で足していくと、それは DBMS を書き直しているのと同じことになります。
先ほどの同時登録を DBMS に任せると、2 件目は 1 件目が書き終わるまで数ミリ秒だけ待たされ、そのあと確実に追記されます。待たせるかどうかを決めているのは DBMS で、アプリのコードには何も書きません。同じことをファイルでやろうとすると、鍵の役目をするファイルを作り、取り損ねたときの再試行を書き、プロセスが落ちて鍵が残ったままになったときの掃除まで書くことになります。
もちろん万能ではありません。学習と運用の手間がかかり、列を 1 つ足すのにも段取りが要ります。1 人しか触らない設定ファイルや、消えても作り直せる一時データなら、ファイルのままで十分です。判断の軸は「消えては困るか」「同時に触られるか」「壊れたデータを弾きたいか」の 3 つです。