なぜデータベースが要るのか
読了目安 約3分
競プロにはなかった「データを残す」という要求から出発して、リレーショナルデータベースと SQL を導入します。
この章の目次
実行が終われば消えてよかった
競プロのプログラムは、答えを出力したら終了し、途中で作った配列や map もメモリから消えます。 答えは出力済みなので、それで困りません。
Web サービスは事情が違います。 サーバーのプログラムは配置のたびに再起動し、不意にクラッシュもしますが、掲示板の投稿は明日もあさっても表示できなければなりません。 このように、プログラムの寿命を超えてデータを残すことを永続化と呼びます。
変数に持てばいいのではないか
投稿を Go の変数(slice や map)に持つ実装は、サーバーが再起動した瞬間にすべての投稿が消えます。 メモリ上のデータはプロセスと運命を共にするので、永続化の要求をそもそも満たせません。
ファイルに書けばいいのではないか
ファイルはプロセスが死んでも残るので、永続化はできます。 しかし、別の問題が二つ出てきます。
- 同時アクセス:Web サーバーは複数のリクエストを同時に処理する。二つのリクエストが同じファイルに同時に書き込むと、内容が混ざったり、片方の書き込みが丸ごと失われたりする。
- 検索の遅さ:「ユーザー alice の投稿だけ欲しい」ときも先頭から全部読むしかなく、投稿が N 件なら O(N) かかる。
「消えない」「同時に読み書きしても壊れない」「速く探せる」の三つをまとめて引き受けるソフトウェアがデータベース(以降 DB とも書きます)です。 アプリはデータの保管と検索を DB に任せ、リクエストの処理に集中します。
リレーショナルデータベースと MySQL
本サイトで扱うのは、データを表の形で管理するリレーショナルデータベース(RDB)です。 その実装として、ISUCON の過去問でもほとんどの年で登場する MySQL を使います。
RDB では表のことをテーブルと呼びます。 テーブルは、型の決まった列を持つ行の集まりです。 ユーザーを入れるテーブルはこんな形です。
users テーブル
+----+-------+-------------------+
| id | name | email |
+----+-------+-------------------+
| 1 | alice | [email protected] |
| 2 | bob | [email protected] |
+----+-------+-------------------+Go で言えば、ID int、Name string、Email string のフィールドを持つ struct のスライスに近い形です。
1 行が struct の 1 つの値、1 列が 1 つのフィールドに対応します。
SQL は「何が欲しいか」を書く言語
テーブルの読み書きには SQL という専用の言語を使います。 競プロでは、ループや二分探索といった「どう探すか」の手続きを自分で書きます。 SQL では「users テーブルから name が alice の行をくれ」のように「何が欲しいか」だけを書き、どういう手順で探すかは DB が決めます。
このように、手続きではなく欲しい結果を記述するスタイルを宣言的と呼びます。 探し方の工夫(データ構造と計算量の話)は DB の中に隠れており、その中身は /sql/07-index/ で開けます。