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

【データベースの知識】SQLが実行されるまでの内部ステップ


私たちがSQLを1行実行したとき、データベースの内部では瞬時にいくつかの工程が実行されています。この「実行ステップ」を知ることで、なぜ同じ結果を返すクエリでも速度が変わるのか、その理由が見えてきます。

1. SQL実行の4つの主要ステップ

【 基本 】 送信されたSQL文は、データベースエンジンによって以下の順序で処理されます。特に「実行計画」の作成は、クエリの成否を分ける心臓部です。

[ 処理の流れ ]
1. 構文解析(Parsing):SQLの文法に誤りがないかチェックし、意味を解析します。
2. 実行計画の作成(Optimization):インデックスを使うか、どの結合法を選ぶかなど、最も効率的なルートを計画します。
3. コンパイル:作成された計画を、データベースが実行可能な形式に変換します。
4. SQLの実行:実際にデータへアクセスし、結果を返します。

2. 各フェーズで何が行われているか

各ステップの詳細を見てみましょう。エンジニアが意識すべきは、特に「2」のプロセスです。

構文解析の壁:キーワードの綴りミスや、存在しないテーブルの指定などはここでエラーとなります。
オプティマイザの判断:統計情報を元に「実行計画(実行の設計図)」を作ります。ここでの判断ミスがスロークエリの原因になります。
キャッシュの活用:一度解析したSQLは「共有プール」に保存され、2回目以降はステップ1〜3を省略して高速化(ソフトパース)される仕組みがあります。

3. まとめ:実行ステップを意識するメリット

「なぜバインド変数を使うべきなのか」「なぜ統計情報の更新が必要なのか」といった疑問の答えは、すべてこの実行ステップの中にあります。

効率化のコツ
・バインド変数を使うことで、再解析(ハードパース)のコストを減らせる。
・最新の統計情報を保つことで、最適な実行計画を立てさせることができる。
・複雑なクエリは、実行計画を確認(EXPLAIN)してボトルネックを特定する。


SQLをただの「命令文」としてではなく、DB内部の「プロセス」として捉えることが、脱・初心者への近道です。


PR

【データベースの知識】結合(JOIN)アルゴリズムの選択と最適化


データベースを扱う上で避けて通れないのが「テーブル結合(JOIN)」です。SQLを書けば結果は同じに見えますが、内部のアルゴリズム選択ひとつで、処理速度は100倍、1000倍と劇的に変わります。今回は実務で役立つ3つの主要アルゴリズムを解説します。

1. 主要な3つの結合アルゴリズム

【 基本 】 データベースが2つのテーブルを繋ぐ際、主に以下の3つの手法から最適なものを選択します。それぞれ「得意なデータ量」と「リソースの使い方」に明確な違いがあります。

Nested Loop Join(入れ子ループ法)
外側の表から1行ずつ取り出し、内側の表を走査して一致を探します。少量のデータに強く、インデックスの活用が前提となります。
Sort Merge Join(ソートマージ法)
両方の表を結合キーでソートし、端から順に突き合わせます。大量データに強く、不等号結合(<, >)でも利用可能です。
Hash Join(ハッシュ結合)
片方の表からメモリ上にハッシュテーブルを作り、もう片方と突き合わせます。大量データ同士の等価結合(=)において非常に強力です。

2. 特徴比較表:データ量とインデックス

【 ポイント 】 実行計画を確認する際、現在のデータ量に対して適切な方法が選ばれているかを判断する基準を持っておくことが重要です。

アルゴリズム得意なデータ量インデックス備考
Nested Loop 1件〜少量 必須 オンライン処理の基本
Sort Merge 大量データ あれば尚可 ソートのCPU負荷あり
Hash Join 大量データ 不要 メモリ(ワークエリア)を消費

3. パフォーマンス改善:DBへの介入術

通常、DBは統計情報を元に自動で判断しますが、判断を誤ることもあります。その際、エンジニアが特定のアルゴリズムを強制・誘導する方法は製品ごとに異なります。

[ 製品別の介入方法 ]
Oracle(ヒント句):/*+ USE_NL(a b) */ のように、SQL内に直接指示を書き込みます。
PostgreSQL(パラメータ):SET enable_mergejoin = off; 等で特定の機能を無効化し誘導します。
MySQL(インデックスヒント):USE INDEX を指定することで、間接的にNLJなどへ誘導します。


結合アルゴリズムの仕組みを知ることは、スロークエリの根本原因を特定し、最適なパフォーマンスを引き出す第一歩となります。


【データベースの知識】MVCCとロックの関係


データベースの並行性を高める技術「MVCC(Multi-Version Concurrency Control)」。これによって「読み取りと書き込みがブロックされない」仕組みが実現されていますが、すべてのロックが不要になるわけではありません。

1. 更新時の動作とロックの役割

【 基本 】 MVCC環境下でも、データの更新(UPDATE/DELETE)時には「排他ロック」を取得します。これは、複数のトランザクションが同時に同じ行を書き換えてしまう「ロストアップデート」を防ぐためです。

[ 更新のポイント ]
更新時のロック:対象行に対して排他ロックを取得します。原則として「行レベル」でロックされます。
更新 vs 更新:同じ行を更新しようとすると、先行する処理が終わるまで「ロック待ち」が発生します。
必ず行ロックか?:通常は行単位ですが、大量の行を一度に更新する場合やインデックス再構築時には、効率化のため「テーブルロック」へ格上げ(エスカレーション)されることがあります。

2. 「読取り」と「書込み」の関係

【 基本 】 MVCCの最大のメリットは、読み取り(SELECT)がロックを取得しないことです。書き込み中であっても、読み取り側は「その処理が始まる前の古いバージョン(多版)」を参照するため、互いに待ち時間が発生しません。

[ ロックの競合 ]
更新 vs 読み込み:ロック待ちなし(読取り側は古い版を見る)。
読み込み vs 更新:ロック待ちなし。
参照一貫性:スナップショットを見ることで、長時間実行される検索も一貫性が保たれます。

3. まとめ:MVCCとロックの整理

質問の答えを整理すると、以下のようになります。この仕組みにより、高いスループットが実現されています。

[ Q&A 形式での整理 ]
1. 更新の際にロックは取得するか?
→ はい。整合性を守るために必須です。原則として「行ロック」がかかります。
2. 更新と読み込みでロック待ちはあるか?
→ いいえ。MVCCにより、読み取りはロックを無視して実行可能です。
3. 更新と更新でロック待ちは発生するか?
→ はい。同一データへの同時書き込みは、必ず順番待ちが発生します。


基本は「行ロック」ですが、処理の規模によっては「テーブルロック」になる可能性も意識しておくと、より深いデータベース設計が可能になります。


【データベースの知識】直列可能性(Serializability)と線形可能性(Linearizability)


一貫性のあるデータ操作を理解する上で、「直列可能性」と「線形可能性」は非常に重要な概念です。どちらも「正しく動く」ことを保証するためのルールですが、その焦点は異なります。

1. 直列可能性(Serializability)

【 基本 】 複数のトランザクションを並列に実行した結果が、それらを「何らかの順序で一つずつ順番に(直列に)実行した結果」と同じになることを保証します。これは「トランザクション」の境界を守るための概念です。

[ 直列可能性のイメージ ]
T1: [---A---]
T2: [---B---]
並列実行しても、結果が「T1 → T2」または「T2 → T1」の実行結果と一致すればOK。
焦点:複数操作(トランザクション)の整合性
範囲:データベース全体の整合性

2. 線形可能性(Linearizability)

【 基本 】 単一のオブジェクトに対する操作が、「ある一瞬」で完了したかのように見えることを保証します。書き込みが完了した瞬間、その後の読み込みは必ず最新の値を返す必要があります。「リアルタイム性」を重視する概念です。

[ 線形可能性のイメージ ]
書き込み: [--- Write(X=10) ---]
読み込み: [--- Read(X) ---] → 必ず 10 が返る
焦点:単一オブジェクト、単一操作の最新性
範囲:時間軸に沿った最新情報の提供

3. まとめ:違いのポイント

この二つは独立した概念ですが、組み合わせて「厳密な直列可能性(Strict Serializability)」として実装されることもあります。

直列可能性:並列実行しても、順番にやったのと同じ結果になる(マルチステップ重視)
線形可能性:操作が完了した瞬間に全員が最新値を見れる(時間的即時性重視)


システムの要件に応じて、どのレベルの整合性が必要かを見極めることが、堅牢なシステム設計の第一歩となります。


【OSS-DB Silver対策】GRANT文とPUBLICの意味


OSS-DB Silver試験対策シリーズ、今回は権限付与を行うSQL文、`GRANT`で使用される特殊なキーワード「PUBLIC」について解説します。誰に対して権限を与えているのか、その範囲を正確に把握しましょう。

1. GRANT文におけるPUBLICとは

【 基本 】 `GRANT SELECT ON TABLE1 TO PUBLIC` のように記述した場合、この「PUBLIC」は、現在および将来のすべてのユーザ(ロール)を指す特殊なグループとして機能します。

[ PUBLICのポイント ]
全ユーザが対象:個別に権限を与えていないユーザも含め、すべてのユーザが対象となります。
自動適用:PUBLICに権限を付与した後に作成された「新しいユーザ」にも、自動的にその権限が適用されます。
暗黙のグループ:PUBLICという名前の特定のユーザが存在するわけではなく、一種の「全員参加のグループ」として扱われます。

2. 試験対策問題:4択チェック

【 問題 】 次のSQL文を実行した場合の「PUBLIC」の説明として、最も適切なものはどれですか?
GRANT SELECT ON TABLE1 TO PUBLIC;

問題:GRANT文の付与対象に指定された「PUBLIC」が指す範囲を選びなさい。

1. データベースを作成した所有者(オーナー)のみを指す。

2. システム管理権限(スーパーユーザ)を持つユーザのみを指す。

3. その時点で存在するユーザのみを指し、後から作成されたユーザは含まれない。

4. すべてのユーザ(ロール)を指し、将来作成される新しいユーザも含まれる。

3. 正解と解説

正解:4

【 解説 】
1. 理解のコツ: `PUBLIC` は「全員」という意味です。PostgreSQLでは、個々のユーザに権限を割り当てる手間を省くために、全ユーザに共通の権限を与えたい時にこれを使用します。
2. 復習の視点: 逆に権限を取り消したい場合は `REVOKE SELECT ON TABLE1 FROM PUBLIC;` と記述します。デフォルトで一部のオブジェクトにはPUBLICに権限が割り当てられていることもあるため、セキュリティ設定の際にも重要な知識となります。


4. まとめ

「PUBLIC = 全ユーザ(未来のユーザも含む)」。このシンプルな定義を覚えておけば、SQLの権限問題で迷うことはありません。試験では「既存のユーザのみ」というひっかけ選択肢がよく出るので、注意してくださいね!