PR
 先に公開した記事「SQL Serverの基本ストレージ・モデルとディスク・スペース管理手法」では,SQL Serverの各テーブル(またはインデックス)に格納するデータの形式には三つのタイプがあることを説明した。通常の行内(IN_ROW)データ,ラージ・オブジェクト(LOB)データ,そしてSQL Server 2005で新たに追加された行オーバーフロー(ROW_OVERFLOW)データである。

 複数の可変長列を含むテーブルの行サイズは,通常は最大行サイズの8060バイト以内に収まっている。しかし,場合によってはそれを超えることがあるので,そのようなテーブルを使うユーザーにとって行オーバーフロー機能は非常に便利である。ここでは,SQL Serverで新しく追加された行オーバーフロー・データがどのように処理されているかを見てみよう。

大きなサイズの行

 SQL Server 7.0以降,最大行サイズに関して行われた最初の変更は,行のデータの一部を実際のデータ・ページとは別のページに格納する機能の追加である。SQL Server 7.0では,データ・ページのサイズが2KBから8KBに変更された。

 ページ・サイズが大きくなったことで,データ行の最大サイズもそれに合わせて大きくなった。最大行サイズは,SQL Server 6.5では1962バイトだったが,SQL Server 7.0では8060バイトに増加した。ただし,どちらの最大行サイズにも,物理ページに行とともに格納されるオーバーヘッドのバイト数が含まれているので,テーブルに定義されているすべての列のサイズの合計値は,最大行サイズよりも多少小さめの値である必要がある。

 実際,SQL Server 2005では最大行サイズが(すぐ後で説明するように)SQL Server 2000と同じ最大行サイズに制限される場合がある。それを超える行サイズのテーブルを作成しようとすると,これまでとは異なるエラー・メッセージが表示される。

 例えば,リスト1に示すように合計サイズがちょうど8060バイトになるように列を定義したCREATE TABLEステートメントをSQL Server 2005で実行すると,図1に示すエラー・メッセージが表示される(このエラー・メッセージとこの記事で示されているコード行はスペースの制約のため折り返され,複数行で表示されていることに注意)。

リスト1:8060バイトの固定長データを持つテーブルを作成する

USE tempdb
GO
CREATE TABLE bigrows
   (a char(3000),
   b char(3000),
   c char(2000),
   d char(60) )
GO

図1:SQL Server 2005の行オーバーフロー・エラー・メッセージ

 このメッセージから,SQL Server 2005が行に格納するオーバーヘッドが7バイトであること,および一部の行では以前のサイズ制限が適用されることがわかる。SQL Server 2005では,固定長の列がすべて通常のIN_ROWデータ制限に収まっている場合に限り,可変長の列だけが専用の行オーバーフロー・ページに格納される(リスト1で作成しようとするテーブルの列はすべて固定長である)。

 次に,すべての列が可変長であるようなテーブルについて調べてみよう。リスト2のコードを実行して,最大定義長が8060バイトを大幅に超える行を持つテーブルを作成する。このCREATE TABLEステートメントをSQL Server 7.0で実行すると,エラー・メッセージが表示されて,テーブルは作成されない。SQL Server 2000ではテーブルは作成されるが,警告が表示される。筆者が試したのはすべてvarchar,varbinary,nvarchar,およびsql_variantのいずれかの型の列だったが,CLRユーザー定義型の列も行オーバーフロー・データ・ページに格納される場合がある。

リスト2:最大行長が8Kバイトを超えるテーブルを作成する

USE tempdb
GO
CREATE TABLE bigrows
  (a varchar(3000), b varchar(3000),
  c varchar(3000), d varchar(3000))
GO

 SQL Server 2005では,リスト2のコードを実行しても警告は表示されない。その後,合計サイズが8060バイトを超えるような複数の可変長列を行に追加した場合,リスト3に示すステートメントの行の挿入は正常に実行される。

リスト3:合計で8Kバイトを超える列を持つ行を挿入する

INSERT INTO bigrows
  SELECT REPLICATE('a', 2100),
    REPLICATE('b', 2100),
    REPLICATE('c', 2100),
    REPLICATE('d', 2100)