先日データベーススペシャリスト試験(2回目)を受験してきました。
さすがに二回目なのでがっつり勉強したわけですが、試験対策本や初学者向けの技術書ではデータベースの仕組み的なところがさっぱり書いていないと感じました。
特に物理設計系の問題は解説を呼んでもフワフワとしか理解できませんでした。
データベーススペシャリストの学習にあたり必須となる (本来対策本に細かく書くべき) 基礎知識をメモします。
(正規化やSQLについては触れません。)
誤り等あればご指摘いただけると幸いです。
※半分下書き状態のため、適宜更新していきます。
※実行計画の中身やインデックスについては、紹介ページいっぱいあると思うので本記事では割愛します。
データベースの構造
データベースの仕組みを理解するためには、データベースが利用する記憶領域を把握しておく必要があります。
大きく分けて揮発性のメモリと不揮発性のディスクに分けられます。ちなみに、メモリは揮発性のためシステムトラブルでデータが失われますが、ディスクは不揮発性なのでデータを保持します。
※色々な呼び方があるので、下記の呼び方は一例です。
メモリ
メモリはディスクの内容を処理するときの一時領域として利用されます。ディスクから読み出すときは一時的にメモリにデータを配置して、ディスクへ書き出すときはメモリに一時的に保存してからディスクへ書き出します。
ここではDBの仕組み理解に必要となる「データベースバッファキャッシュ」「ログバッファ」「共有プール」について紹介します。
データバッファ:ディスクからデータを読み出すときはまずメモリ上のデータバッファ)にデータをもってきて、処理に使用されます。
ログバッファ:RDBMSはログを生成すると、まずメモリのログバッファに書き出します。ディスクへの書き込みはログの生成と別タイミングで実施されます。
共有プール:使用された実行計画は元のSQL文と共に一時的に共有プールにストックされます。SQLの実行時は最初に共有プールに同じSQLが保存されていないか検索し、同じSQLがストックされていればその実行計画を使いまわします。
ディスク
データファイル:実際にDBのデータが格納される領域です。データを読み出すときはページと呼ばれる単位毎にメモリに一時保存して読み出します。また、データの更新時はデータバッファに保存するのみでディスクへは反映しません。非同期にチェックポイントと呼ばれるタイミングでディスクに変更を書き出します。ちなみに、チェックポイントではログもログバッファからログファイルへ書き出されます。
ログファイル:更新前ログや更新後ログが保存されます。ログはログバッファに一時的に書かれていた情報がコミットのタイミングやチェックポイントのタイミングでディスクに書き出されます。(=ログの生成タイミングとは非同期です。)
SQL実行時の流れ
SQLが実行されるとDBMSは①SQLの解析、②実行、③結果の返却を行います。
①SQLの解析
DBMSはデータへアクセスする前にDBMSはアクセス方法を決めてからデータへアクセスします。このアクセス方法のことを実行計画と呼び、SQLの解析により実行計画を決めます。
まず、SQL実行後に共有プールを検索して、今回実行するSQLを同じSQLがないか検索します。同じSQLがあれば、実行計画を作成せずに共有プールにある実行計画をそのまま採用します。
ただし、大文字or小文字等ほとんど完全一致しないと採用されないらしいです。(もちろんDBMSの仕様次第です。)
共有プールに同じSQLが存在しなければ、実行計画を作成します。
SQLの構文をチェックして誤りがないか確認した上で、データディクショナリ(統計情報)へアクセスして実行計画を決めるための情報収集を行います。
データディクショナリが得た統計情報(データ数、インデックス、カーディナリティ等)から実行計画を決めます。(この機能をオプティマイザと言います。)
②SQLの実行
実行計画に基づいてSQLを実行するわけですが、データ参照時には毎回データバッファに欲しいデータがないか検索します。
データバッファに欲しいデータあればディスクとのI/Oが不要となるので、データバッファ上のデータを参照、更新します。
ちなみに、このデータバッファを検索して、データバッファに欲しいデータなければデータファイルから持ってくる営みはインデックス使用時にも行われます。
(データベーススペシャリスト試験ではインデックスはバッファヒット率100% = 【必ずバッファにある】、データはバッファヒット率0% = 【必ずバッファにない】なことが多い気がします。)
バッファに欲しいデータがない場合は、ディスクへ検索をいきます。
ディスクの検索では、処理対象(条件に適合するか確認する全データ)をページごと(データブロックごと)データバッファにロードしてから欲しいデータに合致するか確認します。
③結果の返却
ユーザへ結果を返却します。特筆する説明も特にないです。
コミット
コミットをするとデータの更新が確定されます。この時、トランザクションとして更新が確定するだけでなく、ログバッファ全データのディスクへの書き出しを行います。
ログバッファの内容をコミット時に書き出しているので、システムトラブルでバッファの内容が失われても、ディスクへ書き出されているのでログを用いてデータベースを復旧できるわけです。
ただし、データキャッシュの内容はcommit時には書き出されません。
(ログの書き出しは順次書き込みなので高速なのに対して、ディスクへの書き込みはランダムアクセスが発生して低速なためです。)
データキャッシュからデータファイルへの書き込みはチェックポイントと呼ばれるタイミングで別途実行されます。(チェックポイントを題材にした問題もあった気がします。)
【おまけ】記憶領域
表領域
データベーススペシャリスト試験ではページの話しか登場しませんが、もっと大きな単位があります。
まず表領域という概念があります。1つの表領域に対して複数の物理ファイルが対応付けられ、同時に1つの表領域に対して複数のテーブルを対応づけることができます。
どの表領域にどのデータが格納されるかユーザが意識することはありませんが、表領域とテーブルの対応付けを設計することで、テーブルごとに物理ファイルを分けたりすることができます。
エクステント
行を追加すると使用する記憶領域を確保する必要があります。
記憶領域の確保には複数ページが入るエクステントという単位で行われ、エクステント内の領域を使いきるとさらにエクステントを確保します。
ちなみに、データ更新時に元々確保している領域では不足してしまった場合は新たな領域(エクステント単位)を確保してデータを格納した上で、元の行にはそこに対応するポインタを格納したりします。