バッファ管理

SQL Server データベースの主な目的はデータの格納と取得なので、データベース エンジンの主要な特性は頻繁なディスク I/O ということになります。ディスク I/O 操作は多くのリソースを消費するうえ、完了するのに比較的長い時間がかかるので、SQL Server では I/O の効率を上げることに重点を置いています。バッファ管理は、この効率向上を実現するための重要なコンポーネントです。バッファ管理コンポーネントは 2 つのメカニズムから構成されています。1 つはデータベース ページに対するアクセスと更新を行うバッファ マネージャで、もう 1 つはデータベース ファイルの I/O を削減するバッファ キャッシュ (バッファ プール) です。

バッファ管理のしくみ

バッファはメモリ内の 8 KB のページで、データ ページやインデックス ページと同じサイズです。したがって、バッファ キャッシュは 8 KB 単位のページに分割されます。バッファ マネージャは、データベース ディスク ファイルのデータ ページやインデックス ページをバッファ キャッシュに読み取って、変更されたページをディスクに書き戻すための機能を管理しています。バッファ マネージャが別のデータを読み取るためのバッファ領域を必要とするまで、そのページはバッファ キャッシュ内に残ります。データに変更が加えられた場合だけ、そのデータがディスクに書き戻されます。バッファ キャッシュ内のデータは、ディスクに書き戻す前に何度でも変更できます。詳細については、「ページの読み取り」および「ページの書き込み」を参照してください。

SQL Server を起動すると、システムの物理メモリの量、構成されたサーバー スレッドの最大数、さまざまなスタートアップ パラメータなど、数多くのパラメータに基づいてバッファ キャッシュの仮想アドレス空間のサイズが計算されます。SQL Server では、この計算された量のプロセス仮想アドレス空間 (メモリ ターゲット) をバッファ キャッシュ用に予約しますが、現在の負荷に必要な量だけ物理メモリを獲得 (コミット) します。sys.dm_os_sys_info カタログ ビューの bpool_commit_target 列と bpool_committed 列に対してクエリを実行すると、メモリ ターゲットとして予約されているページ数と、バッファ キャッシュ内で現在コミットされているページ数をそれぞれ返すことができます。

SQL Server の起動からバッファ キャッシュがメモリ ターゲットを取得するまでの間隔を、割り当て増加といいます。この間、読み取り要求によって、必要に応じてバッファが使用されます。たとえば、1 ページの読み取り要求では、1 つのバッファ ページが使用されます。つまり、割り当て増加は、クライアント要求の数や種類によって異なります。1 ページずつの読み取り要求を 8 ページ分の要求にまとめて変換することで、割り当て増加を高速化しています。これにより、特に多くのメモリが搭載されたコンピュータでは、割り当て増加が非常に高速に完了します。

バッファ マネージャはほとんどのメモリを SQL Server プロセスで使用するので、メモリ マネージャと連携して他のコンポーネントでバッファを使用できるようにします。バッファ マネージャは主に次のコンポーネントと対話します。

  • リソース マネージャ。全体的なメモリ使用量を制御します。32 ビット プラットフォームではアドレス空間の使用量を制御します。

  • データベース マネージャおよび SQL Server オペレーティング システム (SQLOS)。低レベルのファイル I/O 操作を行います。

  • ログ マネージャ。先行書き込みログ記録を行います。

サポートされている機能

バッファ マネージャは、次の機能をサポートしています。

  • NUMA (non-uniform memory access) に対応しています。バッファ キャッシュ ページはハードウェア NUMA ノード間に分散されます。そのため、スレッドは外部メモリからではなく、ローカルの NUMA ノードに割り当てられているバッファ ページにアクセスすることができます。詳細については、「SQL Server での NUMA のサポート状況」を参照してください。NUMA を使用している場合にメモリのページがバッファ キャッシュから割り当てられるしくみを理解するには、「NUMA 環境下でのバッファ プールの拡張と縮小」を参照してください。

  • ホット アド メモリをサポートしています。そのため、ユーザーはサーバーを再起動することなく物理メモリを追加できます。詳細については、「ホット アド メモリ」を参照してください。

  • Microsoft Windows XP 32 ビット プラットフォームと Windows 2003 32 ビット プラットフォームで AWE が有効になっている場合、動的メモリ割り当てをサポートしています。動的メモリ割り当てを使用すると、データベース エンジンはバッファ キャッシュ内のメモリを効率的に取得および解放することで、現在のワークロードをサポートすることができます。詳細については、「動的メモリ管理」を参照してください。

  • 64 ビット プラットフォームの大きなページをサポートしています。ページのサイズは、Windows のバージョンに固有です。詳細については、Windows のマニュアルを参照してください。

  • バッファ マネージャは、動的管理ビューによって公開される追加の診断情報を提供します。これらのビューを使用して、SQL Server に固有のさまざまなオペレーティング システム リソースを監視できます。たとえば、sys.dm_os_buffer_descriptors ビューを使用すると、バッファ キャッシュ内のページを監視できます。詳細については、「SQL Server オペレーティング システム関連の動的管理ビューおよび関数 (Transact-SQL)」を参照してください。

ディスク I/O

バッファ マネージャはデータベースの読み取りと書き込みだけを行います。他のファイル操作やデータベース操作 (開く、閉じる、拡張、圧縮など) は、データベース マネージャ コンポーネントおよびファイル マネージャ コンポーネントによって実行されます。

バッファ マネージャによるディスク I/O 操作には、次の特性があります。

  • すべての I/O は非同期で実行されます。つまり、呼び出し側スレッドでの処理中でも、I/O 操作はバックグラウンドで進行します。

  • すべての I/O は affinity I/O mask オプションが使用中でなければ、呼び出し側スレッドで発行されます。affinity I/O mask オプションでは、SQL Server のディスク I/O が、指定した CPU のサブセットに関連付けられます。ハイエンドな SQL Server オンライン トランザクション処理 (OLTP) 環境では、この拡張機能により、I/O を発行する SQL Server スレッドのパフォーマンスを向上できます。

  • 複数ページの I/O は、スキャッタ/ギャザー I/O を使用して実行されます。スキャッタ/ギャザー I/O を使用すると、連続しないメモリ領域との間でデータを転送できます。つまり、SQL Server は、複数の物理 I/O 要求を回避しながら、バッファ キャッシュをすばやく使用またはフラッシュできます。

実行時間の長い I/O 要求

バッファ マネージャは未処理状態が 15 秒以上続いた I/O 要求を報告します。これはシステム管理者が SQL Server の問題か I/O サブシステムの問題かを区別するのに役立ちます。SQL Server のエラー ログには、次のようなエラー メッセージ 833 が報告および記録されます。

SQL Server は、データベース [%ls] (%d) のファイル [%ls] で、完了に %d 秒以上かかった I/O 要求を %d 個検出しました。OS ファイル ハンドルは 0x%p です。最新の実行時間の長い I/O のオフセット: %#016I64x。

実行時間の長い I/O は読み取りまたは書き込みのどちらかの処理ですが、どちらの処理なのかはメッセージに示されません。実行時間の長い I/O のメッセージは、警告であってエラーではありません。SQL Server に関する問題を示すものではありません。これらのメッセージが報告されることにより、システム管理者は、SQL Server の応答時間が遅い原因を追求したり、SQL Server の制御の範囲外にある問題を見分けたりするのに役立てることができます。このように、メッセージに対するアクションは不要ですが、システム管理者は I/O 要求が長時間かかっている理由や、かかっている時間が正当であるかどうかを調べる必要があります。

実行時間の長い I/O 要求の原因

実行時間の長い I/O のメッセージは、I/O が永続的にブロックされていて決して完了しないこと (ロスト I/O ともいいます) を示す場合があります。また、I/O が単純にまだ完了していないことを示す場合があります。この場合、どちらのシナリオなのかをメッセージから区別することはできません。ただ、ロスト I/O の結果、ラッチ タイムアウトが生じることがよくあります。

多くの場合、実行時間の長い I/O は、SQL Server のワークロードによってディスク サブシステムに過度の負荷がかかっていることを示します。ディスク サブシステムが不十分だと、次の現象が発生することがあります。

  • 負荷の高い SQL Server ワークロード中に、実行時間の長い I/O のメッセージがエラー ログに複数記録される。

  • パフォーマンス カウンタに、長時間ディスクが遅延している、長時間ディスク キューに登録されている、ディスクのアイドル時間がないといった情報が表示される。

実行時間の長い I/O は、I/O パス内のコンポーネント (ドライバ、コントローラ、ファームウェアなど) が原因になっている場合もあります。ディスク ヘッドの現在位置の近くにある新しい I/O 要求の処理を優先して、古い I/O 要求の処理を絶えず延期するためです。読み取り/書き込みヘッドの現在位置の最も近くにある要求を優先して要求を処理する一般的な技法を、"エレベータ シーク" といいます。これは Windows システム モニタ (PERFMON.EXE) ツールと連携させるのが困難である場合があります。大半の I/O は速やかに処理されるためです。実行時間の長い I/O 要求は大容量のシーケンシャル I/O を実行するワークロードによって増大することがあります。たとえば、バックアップおよび復元、テーブル スキャン、並べ替え、インデックスの作成、一括読み込み、ファイルの占有領域の解放処理などがあります。

実行時間の長い I/O のうち、以前の状態には関係ないと考えられる孤立した I/O は、ハードウェアやドライバの問題が原因になっている場合があります。システム イベント ログには、問題の診断に役立つ関連イベントが含まれていることがあります。

エラー検出

データベース ページで 2 つのオプションのメカニズム (破損ページ保護とチェックサム保護) を使用して、ページがディスクに書き込まれてから再び読み取られるまでの間、ページの整合性を保証できます。これらのメカニズムによって、データ ストレージだけでなく、ハードウェア コンポーネント (コントローラ、ドライバ、ケーブルなど)、およびオペレーティング システムに至るまで、個々の正確性を検証するための独立した手段が可能になります。この保護はディスクに書き込む直前にページに追加され、ディスクから読み取られた後で検証されます。

破損ページ保護

破損ページ保護は、SQL Server 2000 で導入されたもので、主に電源障害によるページ破損を検出する方法です。たとえば、予期しない電源障害でページの一部だけがディスクに書き込まれた状態になったとします。破損ページ保護を使用すると、ページの 512 バイトの各セクタ末尾に 2 ビットの署名が配置されます (その 2 ビットの元の内容は、署名の配置前にページ ヘッダーにコピーされます)。書き込みが行われるたびに署名としてバイナリの 01 と 10 が交互に設定されるので、セクタの一部だけがディスクに書き込まれたときを常に判別することが可能です。つまり、後でページが読み取られたときにビットの正しくない状態の場合、ページが不適切に書き込まれたので、破損ページが検出されます。破損ページ検出で使用されるリソースは最小限です。ただし、ディスクのハードウェア障害が原因で発生したすべてのエラーを検出できるわけではありません。

チェックサム保護

チェックサム保護は、SQL Server 2005 から導入されたもので、今まで以上に強力なデータ整合性チェックを提供します。チェックサムは各ページに書き込まれるデータから算出され、ページ ヘッダーに書き込まれます。ページにチェックサムが書き込まれている場合は、そのページをディスクから読み取るたびにデータのチェックサムが再計算されます。そして、新しく計算されたチェックサムと、現在書き込まれているチェックサムが異なる場合は、エラー 824 が生成されます。チェックサム保護はページの各バイトの影響を受けるので、破損ページ保護よりも多くのエラーをキャッチできますが、使用されるリソースがやや多くなります。チェックサムが有効になっている場合、電源障害、欠陥のあるハードウェアやソフトウェアが原因で発生するエラーは、バッファ マネージャがディスクからページを読み取るたびに検出できます。

使用されている種類のページ保護は、ページが含まれているデータベースの属性です。チェックサム保護は SQL Server 2005 以降で作成されたデータベースの既定の保護です。ページ保護のメカニズムはデータベースの作成時に指定するもので、ALTER DATABASE を使用して変更できます。ページ保護の現在の設定を確認するには、sys.databases カタログ ビューの page_verify_option 列、または DATABASEPROPERTYEX 関数の IsTornPageDetectionEnabled プロパティを照会します。ページ保護の設定が変更されたとき、新しい設定がデータベース全体にすぐに反映されるわけではありません。個々のページの出力時に、現在のデータベースの保護レベルがそのページに適用されます。つまり、データベースはそれぞれ保護の種類が異なるページで構成されている場合があります。