はじめに
当記事では データベース について概観します。
記事構成としては「そもそもデータベースって何なんだ?」というところから始まり、データベースの歴史や、データベースと関係する重要な用語・概念・機能等についても触れていきます。複数のテーマを取り扱う都合上、どうしても文量が大きくなるため、1つ1つの事柄については深く掘り下げずに話を進めます。
データベースとは?
データベース(英語だと「Database」、また、「DB」と略される) とは ある特定の法則に基づいたデータの集まり や、後述する DBMS (Database Management System) というプログラムが操作可能なデータを指す概念です。厳密な定義はない(はず)ですが、概ねこのような認識が広まっているように思います。
データベースについて理解するとき、注意しておかなければならないことは データベースは概念である ということです。データベースには実体がありません。ちょうど「オブジェクト指向に則って書かれたソースコード」や「オブジェクト指向に基づいて組まれたプログラム」は存在しても、オブジェクト指向そのものは実体として存在しないのと同じようにです。
ただ、実際の開発現場においては、まるでデータベースが実際に存在するかのように会話が展開することがあります。例えば「データベースで異常が発生したぞ!」とか「データベースを更新しないと……」といった感じです。先のオブジェクト指向を再び例にとるならば、オブジェクト指向に沿って書かれたソースコードにバグがあったとき「オブジェクト指向にバグがあったぞ」と言っているようなものなので、よくよく考えるとおかしな話です。
このような状況でいう「データベース」は「データベース化したデータ」を省略したものだったり、後述する DBMS (Database Management System) のことを指していたりするので注意が必要です。必要であれば「データベース」が何を指しているのかを確認したほうがいいかもしれません。
言葉が生まれた日
データベースという単語は第2次世界大戦中に米軍が作った造語とされます。
当時、米軍では作戦資料や情報が様々な施設や基地に分散して保管されていました。しかしながら、そのような管理状況・体制では、機密性とか安全性の観点から問題があるだろうというツッコミが内部から起こったようで、外部からの攻撃や干渉に耐えうる堅牢な施設で集中管理することが考案されました。そのような施設を指して「Database(情報基地、ないし資料基地)」と呼んだのが始まりのようです。
この軍事用語は半世紀近くを経た今日において、IT分野でも使われるようになり、むしろIT用語として広く認識されるまでになりました。ただし、その意味や使われ方は軍事用語とは異なるものです。
意味が生まれた日
IT界隈で用いられる意味・定義の元となったのは、1959年1月に発表された論文 Generalization: Key to Successful Electronic Data Processing(一般化:成功する電子データ処理の鍵) で言及された Source File(源泉ファイル) という概念です。言わずもがな、Source Fileといっても、ソースコードが書かれたテキストファイルのことではありません。
源泉ファイルとは システムに関する完全、かつ正確な情報を含む単一の制御ファイル を指します。言い換えるならば「あるシステムに関係するデータを1つのファイルにまとめたもの」、あるいは「あるシステムに関係するデータは一ヶ所(ないし、いくつかの小数箇所)で、まとめて管理しようという思想」です。
当該論文をGoogle翻訳にかけて読んだ感じですと――1959年当時、ある巨大なシステムを構成する複数の小さなシステムで用いられるデータは、それぞれのシステムごとに定義・実装・保持されていたとされます。私が生まれる以前のことなので、実際のところは分かりませんが、次のように推測することはできます。
例えば、ある企業の業務システムを構成する「給与情報」と「人事情報」というサブシステムが必要とするデータは、それぞれが独自にデータを保持していましたと思われます。おそらく、以下のような感じではないでしょうか。
A 27才 女 250,000
B 22才 男 220,000
C 51才 男 310,000
Aさん,27歳,女性,甲部門,α支店
Bさん,22歳,男性,乙部門,α支店
Cさん,51歳,男性,甲部門,β支店
システムごとに独自の構造を採用していたり、システム同士でデータの重複が見られたり、データの形式(名前の敬称の有無、才と歳、女と女性、みたいな)が違っていたりと色々と混沌としていました。そこで、1つ、ないし少数のファイルで一括して管理しようという源泉ファイルの概念が提唱されたのだと思われます。
DBMSとは?
DBMS (Database Management System) はデータベースを操作するプログラムを指す言葉です。「源泉ファイルの概念を適用したデータ管理体制を実現・支援するためのプログラム」と言い換えてもいいかもしれませんね。
データベース化したデータというのは概ねファイルに保存されるので、DBMSはファイル操作プログラムの一種とみることができるでしょう。ただ、「インメモリデータベース」のような例外もあります。
有名どころのDBMSは概ねアプリという形態を採っています。具体的には以下のDBMSが有名です。
- Oracle Database
- MySQL
- Microsoft SQL Server
- PostgreSQL
- IBM Db2
また、「SQLite」などのライブラリ型のDBMSの少ないですが存在します。
DBMSは凄いんだぜ
DBMSはデータベース操作プログラムの総称であり、処理内容的にはファイル操作プログラムの一種となるのですが、ただのファイル操作処理ではありません。アプリ型のDBMSはサーバー機能を標準搭載しているのが常ですし、加えて、データベース操作を支援する機能を多数搭載しています。
「なんでファイル操作するだけなのに、そんなにたくさんの機能が要るんだよ! 特にサーバー機能なんて要るか?」と思われるかもしれませんが、それはデータをデータベース化する必要があるシステムの性質が関わっています。
データベース化が必要なデータというのは往々にして、様々なアプリやシステム、そしてユーザーから同時・並行的にアクセスされます。それは売上記録かもしれませんし、人事情報かもしれませんし、他ユーザーが登録したサポート用サーヴァントの編成情報かもしれません。
そういった用途では、スタンドアロンなアプリで用いられるファイル・データ操作処理よりも、より優れたパフォーマンスや、データの正しさを保証する仕組みがたくさん必要なのです。いわゆる Concurrency Control(並行性制御、あるいは同時実行制御) です。
例えば、以下のようなデータに新たなデータを追加するケースを考えてみましょう。
Aさん,27歳,女性,甲部門,α支店
Bさん,22歳,男性,乙部門,α支店
Cさん,51歳,男性,甲部門,β支店
Dさん,35歳,男性,乙部門,β支店
このときDBMSは元のデータに新たなデータを追加するわけですが、その処理の途中で別のプロセスが元データを参照したらどうなるでしょうか。もしかすると、以下のような中途半端な状態で表示されるかもしれません。
Aさん,27歳,女性,甲部門,α支店
Bさん,22歳,男性,乙部門,α支店
Cさん,51歳,男性,甲部門,β支店
Dさん,3
ケースバイケースといえばそれまでですが、概ねこのような状態で表示されるのは問題があります。できるならば「変更が加えられる前のデータを取ってくる」か「変更処理が終了するまで待ってからデータを取ってくる」ようにしたいところです。
このような面倒な状況で、適切な処理を行ってくれる仕組みが標準で備わっているのがDBMSの凄いところなのです。
DBとDBMSの歴史
ここからはDBとDBMSの歴史を振り返ります。
世界初のDBMS
世界初のDBMSは、1964年に発表された IDS (Integrated Data Store) です。開発元はGE(General Electric Company)です。
IDSは ナビゲーショナルデータベース というデータ構造を採用しています。ナビゲーショナルデータベースはデータベースの一種で、データ同士に「親」「子」という関係を設定するものです。例えば「『Aさん』は『株式会社α』の社員」「『Aさん』は『人事部』に所属している」「『人事部』は『株式会社α』に属する」みたいな感じです。
■ 株式会社α
├─■ 人事部
└─┴─■ Aさん
最初期のDBMS
IDSに続いたのが、1966年にリリースされた IMS (Information Management System) です。こちらはIBM製のDBMSです。IDSと同様にナビゲーショナルデータベースを採用していましたが、データ同士の関係の組み方はIDSとは異なっています。
IDSではデータ同士の組み方は自由でしたが、IMSでは子データは複数の親データに紐づけることができません。そのため、先の状態をIMSで再現する場合は以下のような構造になります。
■ 株式会社α
└─■ 人事部
└─■ Aさん
微妙に異なるのが分かるかと思います。
IDSで採用している方式は自由に関係性を構築できるのが強みですが、そのぶん構造が複雑になりがちです。対して、IMSで採用されている方式はシンプルで動作速度も早いのですが「Aさんは『人事部』と『営業部』を兼任している」みたいな状況を表そうとするのは苦手です。
■ 株式会社α
├─■ 人事部
│ └─■ Aさん
└─■ 営業部
└─■ Aさん
■ 株式会社α
├─■ 人事部
│ └─■ ...
├─■ 営業部
│ └─■ ...
└─■ 人事部兼営業部
└─■ Aさん
■ 株式会社α
├─■ 人事部
│ └────────┐
├─■ 営業部 │
└─┴────────■ Aさん
同じナビゲーショナルデータベースですが、データの構造(これを データベースモデル という)が違うということで、両者にはそれぞれ名前が付いています。IDSで採用している方法を Network Database Model(網型データベースモデル、あるいはネットワーク型データベースモデル) 、IMSで採用している方法を Hierarchical Database Model(階層型データベースモデル、あるいは構造型データベースモデル) と言います。
リレーショナルデータベースの登場
データベース界隈はナビゲーショナルデータベース一色で、そのなかで網・ネットワーク型と階層・構造型に分かれて争っていました。なお、世界的大企業であるIBMが後者を推したことで、シェアとしては階層・構造型データベースモデルを採用したDBMSが多かったみたいです。
そんな情勢に、新たに切り込んできたのが リレーショナルデータベース 、および Relational Database Model(リレーショナルデータベースモデル) です。リレーショナルデータベースは1970年に発表された新たなデータベースモデルです。
従来のナビゲーショナルデータベースとの違いはいくつかありますが、その1つがデータを指定・参照する方法の違いです。
ナビゲーショナルデータベースで、あるデータを参照するには目的のデータまでのパス、つまり「データの構造」を記述する必要がありました。例えば「./株式会社α/人事部/Aさん」みたいな感じです。対して、RDBは列(カラム)と行(レコード)の組み合わせで目的のデータを参照します。「『会社』列に『株式会社α』とあり、『事業部』列に『人事』とあり、『名前』列に『Aさん』とあるデータ」みたいな感じです。
また、リレーショナルデータベースは 予めデータ同士の関係性を構築しないこと にもあります。ナビゲーショナルデータベースでは、網・ネットワーク型と階層・構造型(他にも、いくつかあるらしい)などの複数の種類がありますが、いずれにせよデータ同士に関係を設定する必要があります。
リレーショナルデータベースは、ナビゲーショナルデータベースの欠点の1つとして指摘されていた データ構造が変化したときにプログラムを書き換える必要がある という欠点を克服しましたが、検索速度が遅いなど一長一短ありました。そのため、コンピューターの性能が低かった1970年当時は商業用として用いられないか、あるいはナビゲーショナルデータベース型のDBMSの補助として用いられる程度に留まっていました。
リレーショナルデータベースの台頭
当初不人気であったリレーショナルデータベースですが、2020年現在に至ってみれば、主要なDBMSの大半はリレーショナルデータベース型のデータベースモデルを採用しています。一部の界隈で、階層・構造型のナビゲーショナルデータベース型のDBMSがリレーショナルデータベース型のDBMSよりも人気だったりするみたいですが、やはり圧倒的に主流なのはリレーショナルデータベースです。
何故こうなったのでしょうか。1つにはコンピューターの性能向上により、処理速度の遅さが問題になりにくくなったということがあるでしょう。ちょうど、Javaテクノロジーの基幹たるJVMが昔は「遅い」と言われていたが、今ではあまり気にされなくなったのと似ているかもしれません(JVMに関してはJVM自体の設計が改良された可能性も十分あるでしょう)。
また、ほとんどのリレーショナルデータベース型のDBMSで採用されている SQL という言語の存在も見逃せません。SQLは クエリ言語 とか 問い合わせ言語 などと呼ばれる言語です。プログラミング言語のように使うことができますが、プログラミング言語とは見做されません。ちょうど、フロントエンドで用いられるHTMLやCSSがプログラミング言語と呼ばれないのと同じ理由でしょう。元々は1974年にIBMが開発した System R というリレーショナルデータベース型DBMSを操作するために用意された SEQUEL (Structured English Query Language) という名前だったのですが、SEQUELという名前がイギリスの「Hawker Siddeley Dynamics Engineering Limited」という会社の商標として登録されているためにSQLに改名した歴史があるみたいです。
NoSQL
ナビゲーショナルデータベース型DBMSを押し退け、デファクトスタンダードになったリレーショナルデータベース型DBMSですが、その普及に伴って、少しずつ欠点と限界が浮かび上がってきました。1つには当初から指摘されていた処理速度の遅さが、やはり気になるということ。もう1つは列と行で構成されるリレーショナルデータベースの特性上、ナビゲーショナルデータベース型のデータを取り扱うのが苦手なことです。例えば、組織図などは階層・構造型のデータはリレーショナルデータベースが苦手するデータ構造の1つです。
このような問題を解決しようと、2000年代後半から盛んになったのが NoSQL という概念です。 リレーショナルデータベースでは解決しにくい問題を解決するために、リレーショナルデータベース以外のデータベースモデルを採用したDBMS や、当該データベースモデルを指す分類の一種となります。
まだまだリレーショナルデータベースを置き換えるには至っていない――というか、NoSQLの定義すら曖昧だったりと、まだまだ成長中の分野と言えます。
リレーショナルデータベース型DBMSのイロハ
最後に、デファクトスタンダードとなったリレーショナルデータベース型DBMSの仕組み・機能・特徴などを、ざっくりと列挙して説明していきます。
表形式のデータに向く
リレーショナルデータベースは列と行からなるデータです。ちょうど、CSVファイルやMicrosoft OfficeのExcelのような感じであり、帳簿型のデータなどを取り扱うときに真価を発揮します。対して、組織図に代表される構造型データなどの扱いは不得意です。
ちなみに、行のことを レコード(Record) 、列のことを カラム(Column) 、レコードとカラムが交わるデータ1つ1つが入る場所を フィールド(Field) と呼んだりします。また、行と列からなるデータのまとまり(Excelでいう「シート」)を テーブル(Table) と言います。
レコードとカラムの役割
リレーショナルデータベースはレコード(行)とカラム(列)から成る表形式のデータですが、Excelのように見映えなどの観点から自由に値を配置したりすることはできません。
まず、カラムごとに格納できる値を指定します。例えば「『商品名』カラムには文字列しか格納できない」「『売価』カラムには0以上の整数しか指定できない」「『商品コード』カラムには8桁の整数のみを許可し、さらにレコード同士での重複を許可しない」といった具合にです。カラムごとに設定した制約により、想定外の値がレコードに保存されることを防いでいるわけです。
そして、データ自体はレコード単位で区別されます。例えば「『売価』が100円以上の『商品名』を検索する」場合、該当する「商品名」フィールドが得られるのではなく、「『売価』が100円以上のレコードを抽出し、さらに、そのレコードの『商品名』を表示する」みたいな処理になるのです。
3論理値
プログラミング言語において、論理値(真偽値とも)は true(真) と false(偽) の2パターンで表現されるのが一般的です。対して、リレーショナルデータベース型のDBMSでは、そこに unknown(不明) を加えた3論理値方式を採用しているものが多いです。
実務において、どこまで意識させられるかは分かりません(少なくとも私は、これで困ったことはありません)が覚えておくに越したことはないでしょう。
トランザクションからの、コミットとロールバック
トランザクション とは それ以上に分けてはならない処理のまとまり のことです。「複数の処理を実行する必要があるが、いずれか失敗した場合、それら処理全てが失敗したと見做す」ときに必要になります。
例えば「Aさんの口座から、Bさんの口座に100万円を送金する」という処理ではトランザクションです。この処理は「Aさんの口座から100万円引く」と「Bさんの口座に100万円足す」の2つの処理から成ります。これら処理の結果として許容されるのは「両方とも成功した」か「両方とも失敗した」のどちらかです。「Aさんの口座から100万円引いたが、Bさんの口座に100万円足すのは失敗した」みたいなのは最悪のケースです。
このようにトランザクションとして登録された処理のまとまりの途中で問題が起こった場合、処理開始前の状態に戻すことを ロールバック(Rollback) と言い、トランザクションに指定された全ての処理が完了したので、処理完了後の状態で登録することを コミット(Commit) と言います。
トランザクション・コミット・ロールバックはデータベース化したデータの「正しさ」を保証する、極めて重要な仕組みの1つです。このような仕組みがDBMS側にない場合はシステム・アプリ側で用意せねばならず、それはかなり面倒くさい処理になるでしょう。
ロックとデッドロック
ロック(Lock) はあるデータ(時として、それはレコードだったりテーブルだったりする)に対して、操作不可属性を付与する機能です。
DBMSというのは同時・並行的に複数のシステムやアプリ、ユーザーなどから操作されるのが常です。このとき、あるデータに対して、同時に操作を加えられたときの挙動を制御するのがロック機能です。具体的には「ある表に新しいデータを追加しているときは、その表の内容を読むことができない。内容を読む処理が実行されたときは、データ追加処理が終わるまで、その処理を待たせる」といった感じにです。
ロックの種類はDBMSごとに色々で、各DBMSの設計思想が強く表れるポイントの1つであるように思います。
また、ロックと似た言葉に デッドロック(Deadlock) があります。初めて聞いたときは「プロレスの技かな?」と思ったりしましたが――いや、そんなことはどうでもよくって――デッドロックとは 複数のトランザクションにより生じたロック同士が衝突し合って処理が止まること です。
例えば、ここに2つのトランザクションがあると仮定します。1つは「Aさんの口座から、Bさんの口座に、100万円送金する」、もう1つは逆に「Bさんの口座から、Aさんの口座に、100万円送金する」というものです。処理の内訳は、まず、送金元の口座から100万円引き、その後、送金先の口座に100万円足すこととします。そしてデータベース上には「Aさん口座」テーブルと「Bさん口座」テーブルがあります。また、どちらのトランザクションも処理途中の場合は処理対象になっているテーブルに対してロックをかけるとします。
このような状況で2つのトランザクションが同時に走ると、1つ目のトランザクションにより「Aさん口座」テーブルから100万円引かれ、同テーブルにロックがかかります。また、それと同時に、2つ目のトランザクションにより「Bさん口座」テーブルから100万円引かれ、同テーブルにロックがかかります。そして両トランザクションが送金先の口座を表すテーブルを操作しようとしたところで、そのテーブルにロックがかかっているために両者のトランザクション処理が停止します。また、お互いに必要とするテーブルにロックを掛け合っているので処理が終了しなくなります。
これがデッドロックです。大抵のDBMSはデッドロック検出処理があるため、デッドロックが発生した場合は原因のトランザクションに対して、ロールバックをかけることで処理を再開させる仕組みになっているはずです。
デッドロックへの対処としては――
- データベース設計をするときに、テーブルの更新順をしっかり決めておく
- トランザクションとしてまとめる処理を小さくして、テーブル・レコードがロックされる時間を短くする
- DBMSのデッドロック検出設定をしっかりと吟味して設定する
- 各DBMSのロックの種類と仕組みをちゃんと理解しておく
――といったことが考えられます。
サーバー機能とODBC
複数のシステム・アプリと同時にやり取りするためにサーバー機能が標準搭載されているケースが多いです。
これと関係してか、何らかのシステム・アプリからDBMSを操作するときは ODBC (Open Database Connectivity) という規格に則った通信でDBMSを制御します。このODBC規格に基づいたDBMS操作プログラムを ODBCドライバー といい、主にライブラリ形式で提供されます。
つまり、あるプログラムからRDBMSを操作するときは、おおよそ以下のようなソースコードになるということです。
require "./odbc_driver.js";
/**
* ※あくまでイメージであり、実際のソースコードとは異なります
*/
const odbc = new ODBCDriver();
const connection = odbc.open("192.168.0.1", "Qii太郎", "114514");
const RESULT = odbc.query(connection, "SELECT name, price FROM sales WHERE price > 100;");
console.log(RESULT);
connection.close();
ODBCドライバーは、各リレーショナルデータベース型DBMSのベンダーが様々な実行環境向けに開発・提供しています。
インデックス
インデックス(Index) はデータを素早く求めるための特殊なデータです。
インデックスについて説明する前にDBMSがデータベースから、どのようにしてデータを抽出しているかを知る必要があります。データベース化したデータを辞書に例えるならば、インデックスが用意されていないデータベースというのは単語が、あいうえお順に並んでいないような状態です。そのためDBMS側は必要なデータを抽出するために全データにチェック処理を実行する必要があります。データ量が小さいうちは処理時間も無視できるほどでしょうが、取り扱うデータ量の増大に伴い、徐々に処理時間が無視できないほどになります。
この問題を解決するのがインデックスです。インデックスは、あるテーブルの任意のカラムのデータを要約したものです。先ほどの辞書で例えるならば、あいうえお順に並び替えたり、文字数ごとに並び替えたり、その単語の分類(名詞・動詞・形容詞など)ごとに並び替えたり――といった感じで整理整頓したものです。このインデックスが用意されていれば、全データを見ることなく、必要なデータのみを求めることができ、処理時間が減少します。
ただし、インデックスは万能ではありません。いくつかの欠点と注意点があります。まず、インデックスはデータなので、インデックスを作るほどにストレージを圧迫します。また、インデックスはインデックス対象となるテーブルと連携しているため、テーブルのデータ追加と連動して、インデックスにもデータの追加が生じ、そのぶんだけ追加処理時間が伸びます。また、定期的にインデックスの内容を最適化する リインデックス という処理が必要になるかもしれません。この処理は結構時間がかかるイメージです。
そして、特に重要なのが インデックスの作り方によってはインデックスが機能しないこと です。例えば「商品コード」「商品名」「原価」「売価」「販売数」のカラムからなるテーブルに対して、「販売数」が100個以上のレコードを求めるとき、このテーブルと紐づくインデックスには「販売数」のインデックスが無くてはなりません。
主キー
主キー(Primary Key) は個々のレコードを区別するカラムに付与する属性です。カラムに付与する属性というと、先述したインデックスのようですが用途が異なります。基本的に主キーを適用したカラムには「NULL禁止(データを格納しないことを禁止)」や「そのカラム内で値の重複を許可しない」といった厳しい制約がセットで付いてきます。
外部キー
外部キー(Foreign Key) とは、あるテーブルのカラムに格納できる値を、別のテーブルのカラムに入っている値のみに制限する機能ことです。例えば、「売上記録」というテーブルの「商品コード」カラムに、「商品情報」というテーブルの「商品コード」カラムとの外部キーを構築することで、「商品情報」テーブルに登録されていない商品コードを使えないようにすることができます。
DBMSの制御方法
リレーショナルデータベース型のDBMSを操作するときに必要なのが SQL です。SQLはIBMで開発された言語で、1974年に発表されました。元々は SEQUEL (Structured English Query Language) という名前でしたが、その名前は英国の「Hawker Siddeley Dynamics Engineering Limited」という会社の商標として登録されていたため、後にSQLへと改名されました。
SQLはあくまでIBM製RDBMSを操作するための言語でしたが、その優秀な言語設計のためか、IBM以外からもSQLの仕様に準拠したRDBMSが次々とリリースされ、RDBMS操作用言語の業界標準となりました。ただ、ベンダーごとにSQLに独自に改修を加えていたために、1986年に標準規格が制定されることになりました。このSQLは 標準SQL と呼ばれることがあります。1986年以降、数年おきに規格のアップデートが行われています。
ただ、標準SQLが作られたものの、必ずしも各ベンダーが準拠しているわけではないことに注意してください。確かに、基本的な文法は各ベンダーとも意識しているようですが、細部(あまり使われることがない機能など)にいくほどに、ベンダー独自要素が増える傾向が見られます。
そして、このようにSQLで書かれた命令文を クエリ(query) と言います。何故「ソース」とか「ステートメント」と言わずに独自の用語を作ったのか、よく分かりませんが、ともかくクエリと呼ぶのです。
CREATE DATABASE sample_database
SELECT
name,
price,
category
FROM
sample_table
WHERE
price > 100 AND category = "fruit"
また、SQLではなく、GUIツールを用いる方法もあります。 Microsoft SQL Server に対応した SSMS (SQL Server Management Studio) や、 MySQL に対応した MySQL Workbench などです。Microsoft Officeの1つである Access を好んで使う人もいます。
さいごに
簡単ではありますが、データベースに関する様々な要素や事柄を、ざっとまとめてみました。私の文章構成力が貧弱なこともあり、かなりの文量になってしまいましたが、その点を考慮しても、データベースの全容を理解するには、まだまだ書き足りないことがたくさんあり、データベースの奥深さを改めて実感させられます。
当記事がデータベース理解の一助となれば幸いです。