忍者ブログ
IT関係の小作人労働の日々の日記です。 最近データベースが好きです。 インフラ構築、DB構築、アプリケーション開発・・・何でも屋です。 何でもできそうで、何にもできない。

【データベース内部構造】SQLはどう処理される?クエリ実行の内部プロセスと最適化の流れ

SQL文を発行した際、データベース(RDBMS)内部ではどのような処理が行われているのだろうか。
SQLは「どのようなデータを取得・更新したいか」という宣言的な記述を行う言語であり、「具体的にどのようにデータを取得するか」という手順はRDBMS内部の処理エンジンが自動的に判断している。

今回は、SQLが投入されてから結果が返されるまでの内部ステップと、効率的な実行処理を行うための「クエリ最適化(Query Optimization)」の流れを整理した。


1. SQL処理の5つのステップ

一般的なRDBMSにおいて、SQL文は主に以下の5つの段階を経て実行される。

  • ① Parsing(構文解析)
    送られてきたSQLの文法的な正しさ(シンタックスチェック)を解釈・検証する。
    SQL実行後の最初のプロセスとして、Parser(構文解析器)がSQLのロジカルな構造を関係演算を表す「Query Tree(クエリツリー)」へ変換する。
  • ② Query Validation(クエリ検証・意味解析)
    SQL内に指定されたテーブルや列(カラム)がデータベース上に実際に存在するか、アクセス権限があるかなどの「意味的妥当性」を検証する。
  • ③ Optimization(最適化 / クエリ最適化)
    関係演算を表す Query Tree を、実際のアクセス手順である「物理的な実行プラン(Execution Plan)」へ変換する。
    通常、データ取得の手順には複数のバリエーション(多くのプラン)が存在するため、その中で最も効率が良い(低コストな)実行プランを選択する。
  • ④ Plan Compile(プランコンパイル)
    クエリオプティマイザ(Query Optimizer)によって選択された最適な計画を、実行エンジンが直接処理できるマシンコードや内部コマンド形式へコンパイル・変換する。
  • ⑤ Execution(実行)
    Query 実行エンジン(Execution Engine)が物理プランに従ってストレージやキャッシュメモリからデータを読み書きし、最終的な結果をクライアントへ返す。

2. クエリ最適化(Query Optimization)の役割

SQLの処理工程の中で、パフォーマンスを決定づける最も重要なコンポーネントが「クエリオプティマイザ(Query Optimizer)」である。

【クエリ最適化の仕組みとポイント】

■ 物理プランの大量生成
1つのSQLに対して、「フルスキャンをするか / インデックスを使うか」「テーブル結合の順序をどうするか」「ハッシュ結合かループ結合か」など、多数の物理プラン候補が生成される。

■ コスト評価(Cost-Based Optimization)
オプティマイザは統計情報(データ件数、インデックスのカーディナリティ、データ配置など)を参照し、推定実行時間やI/Oコストなどの「いろいろな値」から最適なプランを算出・算出決定する。

■ 実行エンジンへの受け渡し
最小コストと判定された計画(最適プラン)のみが選択され、Query 実行エンジンに渡されて高速な処理が実現される。

3. まとめ

SQLは「データ取得の結果」を指示するだけで、裏側ではParser(構文解析器)による Query Tree の生成と、Query Optimizer(最適化エンジン)による物理実行プランの決定という高度な処理が自動的に行われている。

SQLパフォーマンスチューニングにおいては、オプティマイザが意図通りの最適な実行プランを選択できるよう、「最新の統計情報(Statistics)の維持」「適切なインデックス設計」を行うことが重要となる。

【SQL実行プロセスから見るチューニングのポイント】
プレースホルダ(バインド変数)を使い、Parsing・Plan Compileの再利用(ハードパース削減)を狙えているか?
テーブル統計情報は最新に更新されているか?(古い統計情報だとオプティマイザが間違ったプランを選ぶ)
EXPLAIN / AUTOTRACE 等で最適化された物理実行プランを分析しているか?
PR

【データベース】分散システムの限界を示す!CAP定理(CAP Theorem)とは

分散データベースやNoSQLの選定・設計において、避けて通れない非常に重要な理論が「CAP定理(CAP Theorem)」である。
(※一般に「CPA」ではなく「CAP」と呼ばれることが多い概念だ)

CAP定理とは、「分散システムにおいて『一貫性』『可用性』『分断耐性』の3つの性質を、同時にすべて(3つとも)満たすことはできない」というトレードオフの定理を指す。


1. CAP定理の3つの構成要素

分散システムが備えるべき3つの評価軸の定義は以下の通りである。

  • C:Consistency(一貫性)
    システムにあるオペレーションを行った後、どのノード(サーバー)にアクセスしても常に最新で同じデータ(一貫性)が保たれている性質。
    分散システムで一貫性を担保するためには、あるノードでデータ更新(Update)が発生した場合、他のすべてのノードにもその結果を即座に同期・反映しなければならない。
  • A:Availability(可用性)
    システムを構成するノードの一部が故障(ダウン)しても、システム全体としてはレスポンスを返し続け、正常に稼働し続けなければならない性質。
    エラーを返さず、常にすべての正常なノードが読み書きの要求に応答できることが求められる。
  • P:Partition Tolerance(分断耐性)
    ノード間を結ぶネットワークが障害等で分断され、通信が一時的に不通・切断されても、システムとしては停止せずに稼働し続けなければならない性質。

2. なぜ3つ同時に満たせないのか?

ネットワーク分断(P)が発生した状況を想像してみよう。ノードAとノードBの間で通信ができない状態である。

このとき、ノードAに書き込みリクエストが届いた場合、選択肢は2つしかない。

  • 選択肢①:一貫性(C)を優先する ➔ ノードBへデータ更新を同期できないため、エラーを返して書き込みを拒否する。(可用性 A が犠牲になる
  • 選択肢②:可用性(A)を優先する ➔ ノードAだけで書き込みを完了させ、応答を返す。しかしノードBのデータは古いままになる。(一貫性 C が犠牲になる

このように、現実の分散環境において「分断(P)」の発生を完全に回避することは不可能なため、実質的に分散システムは「CP型」か「AP型」のどちらかを選択(トレードオフ)せざるを得ないのである。


3. NoSQLにおけるCAPによる分類

近代のNoSQLデータベースは、この3つのうち「どれを重視し、どれを妥協するか」という設計思想(トレードオフ)によって、大きく3つのタイプに分類することができる。

【CAP特性によるデータベース分類】

■ CP型(一貫性 + 分断耐性)
・特徴:ネットワーク分断時はエラーを返してでもデータ不整合を防ぐ。
・代表例:HBase, MongoDB, Redis, Accumulo
・用途:金融決済や在庫管理など、絶対的なデータ整合性が求められるシステム。

■ AP型(可用性 + 分断耐性)
・特徴:データ整合性が一時的に崩れても、止まらずに読み書きに応答する(※結果的一貫性を重視)。
・代表例:Apache Cassandra, Amazon DynamoDB, CouchDB
・用途:SNSのタイムラインやアクセスログの収集など、止まらないことが最優先のシステム。

■ CA型(一貫性 + 可用性)
・特徴:ネットワーク分断が発生しない単一ノード(非分散環境)を前提とするモデル。
・代表例:従来の単一構成RDBMS(PostgreSQL, MySQL, Oracle DB など)
・注意:分散環境においてはネットワーク障害(P)の回避が困難なため、実質の選択肢としては「CP」か「AP」の2択となる。

4. まとめ

「すべての面で完璧なデータベース」は存在しない。システム要件に応じて、「一貫性(C)」を絶対に譲れないのか、あるいは「高可用性(A)」を取って一時的な不整合(Eventual Consistency:結果的一貫性)を許容するのかを見極めることが、適切なDB選定の第一歩となる。

【CAP定理から考えるデータベース選定の要点】
金融・決済・アカウント管理など、1円・1件のズレも許されない ➔ CP型(または伝統的RDBMS)
ログ収集・SNS・カートの一時保持など、止まらないことが最優先 ➔ AP型
AP型を採用する場合は「結果的一貫性(最終的にデータが合えばOK)」の思想を許容できるか確認する

【Struts1.1再入門】Java 21 + Macで「Welcome!」を表示させる環境構築の手順

Java 21 が標準となった現代の開発現場において、あえて 「Struts 1.1」 の学習に立ち返る。
かつてのWeb開発を支えたこのフレームワークを、最新の Mac OS 15.7.7 上で動かし、当時の構造を解き明かすことは、レガシーシステムの移行や移植サービスを検討する上で非常に価値のある検証となる。

今回は、Tomcat のセットアップから Struts 1.1 サンプルアプリケーション(struts-blank)の稼働確認までを整理した。


1. 現代環境(Mac OS 15.7.7 + Java 21)における Tomcat の準備

Struts 1.1 は 2003 年頃の製品であり、当時の Servlet API 仕様(2.3)に深く依存している。最新の Tomcat 11 などでは動作しない可能性が高いため、今回は安定して動作確認が可能な Apache Tomcat 9.0系 を採用する。

  • Step 1: Tomcat のダウンロードと展開
    公式サイトより apache-tomcat-9.0.120.zip を取得し、ターミナルから unzip で展開・配置する。
  • Step 2: JAVA_HOME の確認
    Temurin-21 のパスが正しく通っていることを確認してサーバーを起動する。
【JAVA_HOME 確認】
% echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home

2. ターミナル操作によるサンプルアプリのデプロイ

今回は、最小構成である struts-blank.war を Tomcat にデプロイし、動作確認を行う。

【デプロイと稼働確認手順】
1. Tomcat 起動:
    ~/opt/tomcat/bin/startup.sh
2. Tomcat 稼働確認:
    ブラウザで http://localhost:8080/ にアクセスし、Tomcat の初期画面が表示されることを確認。

3. サンプル(struts-blank)の配備:
    cp ~/Downloads/jakarta-struts-1.1/webapps/struts-blank.war ~/opt/tomcat/webapps/

4. 動作確認:
    ブラウザで http://localhost:8080/struts-blank/ にアクセスし、「Welcome!」 画面が表示されることを確認。

3. まとめ

最新の Mac OS および Java 21 環境において、Struts 1.1 の土台が完成した。
「Welcome!」画面が表示されたことで、開発環境のベースラインが確保されたことになる。今回の検証で「動く環境」を手に入れたため、次回からはより踏み込んだ内部構造の解析へステップを進めていく。

【次回の検証ポイント】
struts-config.xml の解析: 設定ファイルと Action クラスの紐付けを確認する。
ビルドの自動化: IDEに頼らず、Ant や Maven を使った CLI ビルド環境への昇華。
移植性の検証: レガシーな構成を読み解き、将来の移植サービスへの知見とする。

【データベース】データの信頼性を守る命綱!トランザクションの「ACID特性」とは

データベース(RDBMS)を扱う上で、絶対に避けて通れない最重要概念が「トランザクション(Transaction)」である。
銀行の口座振込やECサイトの注文処理など、複数のデータ更新を「1つの不可分な処理単位」として扱う仕組みを指す。

そして、このトランザクション処理が安全かつ正確に行われるために、RDBMSが保証すべき4つの性質の頭文字をとったものが「ACID(アシッド)特性」だ。
今回は、システム開発やデータベース設計の基本となるACID特性をわかりやすく整理した。


1. ACID特性の4つの要素

データベースのデータ破壊を防ぎ、整合性を完璧に保つためにRDBMSが備えるべき4つの原則は以下の通りである。

  • A:Atomicity(原子性 / All or Nothing)
    トランザクションに含まれる一連のデータ操作は、「すべて完全に実行される(Commit)」か「まったく実行されなかった状態に戻る(Rollback)」かのどちらか一方にしかならない性質。
    途中でエラーやシステム障害が発生した場合、中途半端に一部だけが更新された状態が残ることは絶対にない。
  • C:Consistency(一貫性 / 整合性)
    トランザクションの開始前と終了後で、データベースの整合性制約(主キー制約、外部キー制約、NOT NULL制約など)が常に満たされている性質。
    ルールに違反するような不正なデータ変更が行われそうになった場合、トランザクション全体が自動的に取り消される。
  • I:Isolation(独立性 / 隔離性)
    複数のトランザクションが同時に並行実行されていても、互いの処理過程が干渉・影響し合わない性質。
    他のトランザクションからは「まだ確定していない途中の状態」が見えず、あたかも1つずつ順番に実行(直列化)されたかのような結果が保証される。
  • D:Durability(永続性 / 堅牢性)
    トランザクションが一度確定(Commit)または取消(Rollback)した時点で、その結果は永続的に記憶され、絶対に失われない性質。
    確定直後にサーバーの電源が落ちたりシステム障害が発生したりしても、REDOログ等の仕組みによってデータは確実に復元される。

2. 具体例:銀行の口座振込で考えるACID

「Aさんの口座からBさんの口座へ1万円を振り込む」というトランザクション(①A口座から1万円引く ➔ ②B口座に1万円足す)を例に挙げると、ACID特性の重要性がより明確になる。

【振込処理におけるACIDの役割】
原子性: ①のあと回線が切れても、B口座に足されずにA口座の1万円だけ消える(消滅する)事故を防ぐ(ロールバックされる)。
一貫性: 残高がマイナス不可の制約がある場合、残高不足なら振込処理自体をエラーにして弾く。
独立性: Aさんが振込処理を行っている最中に、CさんがAさんの残高を参照しても「振込途中の確定していない残高」は見えない。
永続性: 「振込完了」の画面が出た直後に銀行のDBサーバーが停電しても、1万円の移動記録は消えずに残る。

3. まとめ

Webアプリケーションや基幹システムにおいて、データの辻褄が合わなくなるバグを防いでいるのは、RDBMSが提供するこのACID特性のおかげである。

システム設計時には、特に「隔離性(Isolation)レベルの設定(Dirty ReadやPhantom Readの防犯)」「デッドロックの防止」など、ACID特性を意識したトランザクション設計を行うことが求められる。

【トランザクション設計のチェック項目】
複数の更新クエリが「1つのトランザクション」としてコミット/ロールバック制御されているか?(原子性)
アプリ側の処理異常時に確実に ROLLBACK が発行される構造になっているか?(一貫性)
同時実行時のロック範囲や分離レベル(Read Committed等)が適切に設計されているか?(独立性)

【データベースの知識】現代のRDBの原点!コッドの12のルール(Codd's 12 Rules)とは

リレーショナルデータベース(RDB)の基礎理論を考案した Edgar F. Codd(エドガー・F・コッド)博士が1985年に提唱した「コッドの12のルール(Codd's 12 Rules)」
「真のリレーショナルデータベース管理システム(RDBMS)とはどうあるべきか」を定義した指針であり、データベースの運用や基本設計、情報処理試験の理論問題においても極めて重要な概念となっている。

今回は、データベースを正しく管理・運用するためにRDBMSが備えるべき12の原則をわかりやすく整理した。


1. コッドの12のルール(RDBMSの要件定義)

コッド博士は、システムが独自の拡張や物理的な制約に頼らず、純粋に「リレーショナルモデル」としてデータの一貫性・独立性を保つために以下の12原則(および原則0である「完全なリレーショナル機能による管理」)を定めた。

  • ① 情報の表現原則(Information Rule)
    テーブル名や列名、制約といったメタデータを含め、データベース内のすべての情報は「表(リレーション)のセルに格納された値」として一元的に記録されなければならない。
  • ② アクセスの保証(Guaranteed Access Rule)
    すべてのデータ要素は、「テーブル名」「主キー(Primary Key)の値」「列(ドメイン)名」の組み合わせによって論理的に一意指定してアクセス可能でなければならない(物理アドレスやポインタの指定は不可)。
  • ③ NULLの統一的扱い(Systematic Treatment of Null Values)
    「値が存在しない(未知)」「適用不能」を表す NULL は、データ型に関わらず、システム全体で統一かつ体系的な方法で処理されなければならない。
  • ④ オンライン・アクティブ・カタログ(Dynamic Online Catalog)
    データベース構造を保持するカタログ(データディクショナリ)自体も通常のデータと同じ表形式で表現され、通常のSQL等のデータアクセス言語を使ってオンラインで照会できなければならない。
  • ⑤ 包括的なデータ言語の原則(Comprehensive Data Sublanguage Rule)
    データの定義(DDL)、ビューの定義、データの操作(DML)、整合性制約、トランザクション制御(COMMIT/ROLLBACK)などが、単一の明確に定義された言語(SQLなど)で完結して実現できなければならない。
  • ⑥ ビューの更新原則(View Updating Rule)
    理論的に更新可能なビューに対して更新(INSERT / UPDATE / DELETE)が発行された場合、RDBMSがそれを検知し、裏側にある実表(基底テーブル)に対して正しく更新処理を反映しなければならない。
  • ⑦ 高水準の挿入・更新・削除(High-Level Insert, Update, and Delete)
    データ操作言語は、一度の命令(クエリ)で1行ずつ処理するのではなく、複数の行(タプル/集合)をひと括りで集合処理できなければならない。
  • ⑧ 物理的データ独立性(Physical Data Independence)
    データの記憶形式やアクセスパス(インデックス構造やファイルの配置場所など)といった物理的な変更を行っても、アプリケーションプログラムのコードに影響を与えてはならない。
  • ⑨ 論理的データ独立性(Logical Data Independence)
    テーブルの分割・結合など、データベースの論理構造を変更した場合でも、既存のアプリケーションプログラムへの影響を最小限に抑えられなければならない(ビュー等の活用)。
  • ⑩ 整合性制約の独立性(Integrity Independence)
    主キー制約や外部キー制約などのデータ整合性制約は、アプリ側のプログラム内に記述するのではなく、RDBMS内のカタログに直接定義・保持されなければならない。制約が変更されてもアプリ側に影響を与えない。
  • ⑪ 分散の独立性(Distribution Independence)
    データベースが複数のサーバやネットワーク上に分散配置されたとしても、アプリケーション側からはあたかも単一のローカルデータベースを操作しているように見えなければならない(位置の透過性)。
  • ⑫ 規約無効化の否定(Non-Subversion Rule)
    RDBMSに低水準(レコード単位など)のインターフェースが存在する場合でも、その経路を使ってRDBMSに定義された整合性制約やセキュリティ規約を回避・破壊できてはならない。

2. まとめ:現代RDBMSにおける位置づけ

コッドの12のルールは、SQLデータベースの理想型を示した厳格な基準である。現実の主要なRDBMS(Oracle、PostgreSQL、MySQL、SQL Serverなど)であっても、これら12のルールを完全(100%)に満たしている製品は少ない。

しかし、「物理データからの独立」「集合操作」「整合性制約のRDBMS側での一元管理」といった根幹のコンセプトは、現代のデータベース設計やアプリケーション開発においても変わらない基礎知識として息づいている。

【データベース設計・運用のチェック項目】
アプリケーション側に整合性チェックのロジックを抱え込みすぎていないか?(ルール10)
物理的なインデックス追加・変更がアプリ側に波及しない構造になっているか?(ルール8)
NULLの判定ロジックがシステム全体で統一されているか?(ルール3)