第8章 データベースの基本概念

データベースとは

データベースは、情報を管理するための電子システムで、データを格納、取得、更新、削除することができます。データベースはコンピュータ上で稼働し、一般的には大量のデータを効率的かつ安全に管理するために使用されます。

データベースの主な特性は次のとおりです。

  • 効率的なデータアクセス:データベースは、大量のデータを迅速かつ容易にアクセスできるようにすることが目的です。これには、データの検索、挿入、更新、削除などの操作が含まれます。SQL(Structured Query Language)などのクエリ言語を用いてこれらの操作を行います。
  • データ整合性:データベースは、データの正確性と一貫性を維持するための機構を提供します。これには、トランザクション制御(すべての操作が成功するか、すべてが失敗するかの「全てまたは無し」の原則)や、データの制約(主キーや外部キーの制約など)が含まれます。
  • データセキュリティ:データベースは、機密データを保護するための機能を提供します。これには、ユーザーアクセスの制御や、データの暗号化が含まれます。
  • データの独立性:データベースは、物理的なデータの格納方法と、そのデータをアプリケーションやユーザーがどのように見るかを区別します。これにより、データの物理的な変更がアプリケーションに影響を及ぼさないようにすることができます。

データベースは種々のタイプがありますが、最も一般的なのはリレーショナルデータベース(RDBMS)で、データは表形式で保管され、SQLで操作されます。MySQLはこのタイプのデータベースの一つです。他のタイプには、NoSQLデータベース(MongoDBなど)、オブジェクト指向データベース、階層型データベースなどがあります。

データベースは、ビジネス、科学、政府、医療など、幅広い領域で使われており、情報を管理し、有用な洞察を得るための不可欠なツールとなっています。


データベースの種類

データベースには様々な種類があります。それぞれが特定のユースケースや要件を満たすように設計されています。以下に、主要なデータベースの種類について解説します。

  • リレーショナルデータベース(RDBMS): RDBMSは現在最も広く使用されているデータベースの形式で、データは表(テーブル)の形で格納されます。テーブルは行(レコード)と列(フィールド)によって構成され、各テーブルは互いに関連付けられています。このタイプのデータベースは、SQL(Structured Query Language)を使用してデータに対する操作を行います。MySQL、PostgreSQL、Oracle DatabaseなどがRDBMSの例です。
  • NoSQLデータベース: NoSQLデータベースは、リレーショナルデータベースの制約を排除した柔軟なデータモデルを持ち、大量のデータを効率的に処理できるよう設計されています。NoSQLは「Not Only SQL」の略で、リレーショナルデータベースとは異なるデータモデルを使用します。主なNoSQLデータベースの種類には、ドキュメントストア(MongoDB、CouchDB)、キー値ストア(Redis、DynamoDB)、カラムストア(Cassandra、HBase)、グラフデータベース(Neo4j、JanusGraph)などがあります。
  • インメモリデータベース(IMDB): インメモリデータベースは、データを主記憶装置(RAM)に保持することで高速なデータアクセスを実現します。これは、ディスクI/Oの遅延を排除することで、リアルタイムの分析やトランザクション処理に役立ちます。ただし、RAMは揮発性であるため、電源が切れるとデータが失われる可能性があります。そのため、永続性を確保するための手段が必要となります。Redis、Memcached、SAP HANAがこのタイプのデータベースの例です。
  • オブジェクト指向データベース(OODBMS): OODBMSは、オブジェクト指向プログラミングの原則をデータベース管理に適用したシステムです。データはオブジェクトとして表現され、オブジェクト間の関係性を表現できます。これにより、より複雑なデータ構造の表現が可能となります。しかし、OODBMSは一般的な使用例が少なく、特定の用途(CAD/CAMシステム、リアルタイムシステムなど)で主に使用されています。
  • タイムシリーズデータベース(TSDB): タイムシリーズデータベースは、時間に関連したデータ(例えば株価の変動、気温の変化、サーバーのパフォーマンスメトリクスなど)を格納し、分析するために特化したデータベースです。タイムスタンプを持つデータを効率的に処理し、分析することができます。InfluxDB、TimescaleDBが例です。
  • グラフデータベース: グラフデータベースは、ノードとエッジを使用してデータ間の関係を表現します。これは、ネットワーク、ソーシャルネットワーキング、レコメンデーションエンジンなどの複雑な関係性を扱う場合に有用です。Neo4j、Amazon Neptuneが例です。
  • JSONデータベース: JSONデータベースは、データをJSON形式で保存します。これにより、データの柔軟性と拡張性が向上します。JSONデータベースは、ドキュメント指向のNoSQLデータベースの一種とも考えられます。MongoDB、Couchbaseが例です。
  • XMLデータベース: XMLデータベースは、XML文書の格納と検索を効率化するために設計されています。これらのデータベースは、XML文書の複雑なクエリを実行する能力があります。eXist-db、BaseXが例です。
  • 分散データベース: 分散データベースは、複数のネットワーク接続ノード間でデータを分散させることで、パフォーマンス、信頼性、可用性を向上させます。データは一元化されず、物理的に複数の場所に保存されます。Cassandra、CockroachDBが例です。

データベースは、Webアプリケーション、モバイルアプリケーション、ソフトウェアのバックエンドなど、多くのシステムで中心的な役割を果たします。例えば、オンラインショッピングサイトでは、商品情報、ユーザー情報、購入履歴などのデータがデータベースに格納され、これらの情報に基づいてサイトが動作します。

これらの知識を学び、理解することはプログラマーにとって重要です。これにより、データを効率的に扱い、高度なシステムを構築するための基礎を築くことができます。


SQLとは

SQL(Structured Query Language)は、データベース操作と問い合わせのための標準的な言語です。リレーショナルデータベース管理システム(RDBMS)で最も広く使用されていますが、非リレーショナルデータベースでも部分的に使用されています。

SQLの起源は、1970年代初頭のIBMにあります。その後、1970年代後半に最初の商用RDBMSであるOracleがリリースされました。SQLは、その一貫性と標準化のためにAmerican National Standards Institute(ANSI)とInternational Organization for Standardization(ISO)によって標準化されました。

SQLは、主に以下の3つのサブセットから成り立っています。

  • データ定義言語(DDL):テーブルやその他のデータベースオブジェクトの構造を定義します。CREATE、ALTER、DROPなどの文が含まれます。
  • データ操作言語(DML):データを操作します。INSERT、UPDATE、DELETEなどの文が含まれます。
  • データ制御言語(DCL):データベースへのアクセスを制御します。GRANT、REVOKEなどの文が含まれます。

多くの大規模企業や組織は、顧客情報、在庫情報、販売データなどを管理するためにRDBMSを使用しており、その操作のためにSQLを使用しています。また、ウェブアプリケーションでも、データを永続的に保存するためにRDBMSとSQLが使用されます。

SQLはまた、データ分析やビッグデータの分野でも広く使用されています。データ分析師やデータサイエンティストは、データベースから情報を抽出、分析するためにSQLを使用します。SQLはデータ操作の基礎であり、その知識は多くのIT職種で求められています。

トランザクション

データベースにおけるトランザクションは、一連の操作(例えば、データの読み取り、書き込み、更新、削除など)の単位を指します。これらの操作は、すべてが成功した場合にのみ確定(コミット)され、1つでも失敗した場合には全て取り消され(ロールバック)、データベースを以前の状態に戻します。

トランザクションは、以下のACID特性を満たす必要があります。

  1. 原子性 (Atomicity):トランザクションは全ての操作が成功するか、全く操作が行われないかのいずれか(「すべてか無し」)である必要があります。もしトランザクションの途中で何らかの問題が生じた場合、それまでに行われた全ての操作は取り消されます。
  2. 一貫性 (Consistency):トランザクションはデータベースの状態を一貫性のある状態から別の一貫性のある状態に変更する必要があります。一貫性とは、全てのデータが特定のルールや制約を満たす状態を指します。
  3. 独立性 (Isolation):複数のトランザクションが同時に行われる場合でも、それぞれのトランザクションは他のトランザクションから分離されている必要があります。これにより、トランザクション間で互いに影響を与えることなく並行して操作を行うことができます。
  4. 持続性 (Durability):トランザクションが一度完了(コミット)されると、その結果は永続的にデータベースに保存されます。システム障害が発生したとしても、コミット済みのトランザクションの結果は失われることはありません。


原子性 (Atomicity)

データベースのトランザクションにおける原子性は、すべての操作が完全に成功するか、あるいは全く操作が行われないかのいずれかを意味します。これを満たさない場合の事例と弊害について考えてみましょう。

例として、銀行の口座間での資金の転送を考えてみましょう。これは、通常、2つの操作からなるトランザクションとして行われます。

  • 口座Aから一定額の資金を引き出す
  • 口座Bにその引き出した額を入金する

これらの操作は一つのトランザクションとして行われ、原子性を持っています。すなわち、両方の操作が成功するか、あるいは両方の操作が行われていない状態になるかです。

しかし、このトランザクションが原子性を満たさない場合、すなわち、操作の途中で何か問題が発生し、口座Aからの引き出しは成功したが、口座Bへの入金が失敗したとします。この場合、お金は口座Aから消えますが、口座Bには追加されません。つまり、お金が「消失」してしまうという問題が発生します。

これは、データの整合性が壊れる重大な問題です。資金の引き出しと入金が一つのトランザクションとして扱われ、どちらか一方でも失敗すれば全体の操作が元に戻され(ロールバックされ)、データの一貫性が維持されます。

これを達成するためには、データベース管理システム(DBMS)がトランザクションをサポートしている必要があります。多くのリレーショナルデータベース管理システム(RDBMS)では、SQLのBEGIN TRANSACTION、COMMIT、ROLLBACK命令を使ってトランザクションを制御できます。

以下にその擬似コードを示します。

BEGIN TRANSACTION;  // トランザクション開始
// 口座Aから資金引き出し
UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = A;
IF SQL%ERRORCODE != 0 THEN ROLLBACK; END IF;  // エラーチェック

// 口座Bへ資金入金
UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = B;
IF SQL%ERRORCODE != 0 THEN ROLLBACK; END IF;  // エラーチェック

COMMIT;  // トランザクションの確定

このように、全体の処理をトランザクションで包むことで、処理が途中で失敗した場合でもデータの一貫性を保つことができます。


一貫性 (Consistency)

データベースのトランザクションでは、一貫性(Consistency)が非常に重要な要素の一つです。一貫性とは、トランザクションがデータベースを一つの整合性のある状態から別の整合性のある状態に遷移することを保証する性質を指します。

一貫性を満たさない事例とその弊害について考えてみましょう。例として、ある学校の学生データベースを考えてみます。このデータベースでは、学生のIDが一意であるという制約(整合性の条件)があるとします。

新しい学生が入学し、データベースに新しいレコードが追加される際、すでに存在する学生と同じIDを持つ新しいレコードが追加されるトランザクションがあるとします。このトランザクションが実行されると、データベースの一貫性が壊れ、同じIDを持つ2人の学生が存在することになります。

この結果、学生の成績の取得や在籍情報の更新などの操作が正しく行えなくなるなど、深刻な問題が生じます。

この問題を防ぐためには、トランザクションの一貫性を保証する必要があります。これは、データベース管理システムが制約の違反を検出してトランザクションを中止(ロールバック)したり、アプリケーションが新しい学生のIDが一意であることを確認したりすることで実現できます。

以下にその擬似コードを示します。

BEGIN TRANSACTION;  // トランザクション開始

// 新しい学生IDが一意であるか確認
SELECT COUNT(*) FROM Students WHERE StudentID = NewID;
IF SQL%ROWCOUNT > 0 THEN
  ROLLBACK;  // IDが一意でない場合、トランザクションをロールバック
  RETURN;
END IF;

// 新しい学生を追加
INSERT INTO Students (StudentID, Name, ...) VALUES (NewID, 'John', ...);
IF SQL%ERRORCODE != 0 THEN ROLLBACK; END IF;  // エラーチェック

COMMIT;  // トランザクションの確定

このように、一貫性を保つためには、トランザクションがデータベースの整合性を破らないことを確認するためのチェックを行うことが重要です。


独立性 (Isolation)

データベースのトランザクションにおける独立性(Isolation)は、複数のトランザクションが同時に行われる場合に、それぞれのトランザクションは他のトランザクションから隔離されているかのように動作することを保証する性質を指します。つまり、あるトランザクションが途中であっても、他のトランザクションにはその影響が見えないようにするということです。

独立性を満たさない事例を考えてみましょう。例えば、銀行の口座間での資金移動を考えてみます。トランザクションAが口座1から口座2へ資金を移動する過程で、トランザクションBが口座2の残高を参照するとします。トランザクションAが完了する前にトランザクションBが参照すると、資金の移動がまだ完了していないため、トランザクションBは正確な残高を得られません。これは、トランザクションBがトランザクションAの中間状態を観察するという、独立性の破壊です。

この状況は一貫性の問題も引き起こし、一時的な残高の不一致や誤った決定(例えば、口座2の残高が不足していると誤って判断する)などを引き起こします。

この問題を解決するためには、データベース管理システムがトランザクションの独立性を保証する必要があります。具体的には、他のトランザクションが完了するまでトランザクションBのような参照をブロックする(これをロックと呼ぶ)か、あるいはトランザクションが開始した時点のデータスナップショットを見せる(これをスナップショット分離と呼ぶ)などの手法があります。

以下にその擬似コードを示します。

BEGIN TRANSACTION A;  // トランザクションA開始
withdraw(Account1, Amount);  // 口座1から引き出し
deposit(Account2, Amount);  // 口座2に入金

BEGIN TRANSACTION B;  // トランザクションB開始
balance = getBalance(Account2);  // トランザクションAが完了するまでブロックされるか、またはスナップショットが表示される

COMMIT TRANSACTION A;  // トランザクションAの確定
COMMIT TRANSACTION B;  // トランザクションBの確定

これにより、各トランザクションは他のトランザクションから独立して動作し、中間状態を観察することが防がれます。


持続性 (Durability)

データベースのトランザクションにおける持続性(Durability)は、一度確定したトランザクション(COMMITしたトランザクション)の結果が永続的に保存され、システムの障害(例えば電源の断など)があっても失われないことを保証する性質を指します。

持続性を満たさない事例とその弊害を考えてみましょう。例えば、ある銀行のシステムで、口座間での資金移動トランザクションが確定したとします。しかし、その後でシステムに何らかの障害(例えば、電源の断やシステムのクラッシュ)が発生し、データベースが直前の状態に復元された場合、確定したはずのトランザクションの結果が反映されていない状態になります。これは、持続性が保証されていない事例と言えます。この結果、重要なビジネスのデータが失われ、信頼性や整合性の問題が発生します。

この問題を解決するためには、データベース管理システムがトランザクションの持続性を保証する必要があります。これは通常、データベースが確定したトランザクションの結果をディスクなどの永続的なストレージに書き込むことで実現されます。また、障害発生時にデータベースの一貫性を維持するために、ログを用いて行われた操作を記録し、障害が発生した場合にはログを元にデータベースを前の一貫性のある状態に戻す(これをロールバックと呼ぶ)といった手法があります。

以下にその擬似コードを示します。

BEGIN TRANSACTION;  // トランザクション開始
withdraw(Account1, Amount);  // 口座1から引き出し
deposit(Account2, Amount);  // 口座2に入金
COMMIT TRANSACTION;  // トランザクションの確定

// この時点で、データベース管理システムは確定したトランザクションの結果を永続的なストレージに書き込む

// もし、ここでシステムに障害が発生した場合でも、確定したトランザクションの結果は保持され、障害が解消された後にもその結果は利用可能

これにより、確定したトランザクションの結果は永続的に保持され、データの信頼性と一貫性が確保されます。