メモリ最適化テーブルのテーブルと行のサイズTable and Row Size in Memory-Optimized Tables

適用対象: ○SQL Server ○Azure SQL Database XAzure SQL Data Warehouse XParallel Data WarehouseAPPLIES TO: yesSQL Server yesAzure SQL Database noAzure SQL Data Warehouse noParallel Data Warehouse

SQL Server 2016 (13.x)SQL Server 2016 (13.x) より前のバージョンでは、メモリ最適化テーブルの行内データのサイズは、8,060 バイトより長くすることができませんでした。Prior to SQL Server 2016 (13.x)SQL Server 2016 (13.x) the in-row data size of a memory-optimized table couldn't be longer than 8,060 bytes. しかし、SQL Server 2016 (13.x)SQL Server 2016 (13.x) 以降および Azure SQL Database では、複数の大きな列 (複数の varbinary(8000) 列など) および LOB 列 (varbinary(max)、varchar(max)、nvarchar(max)) を含むメモリ最適化テーブルを作成し、ネイティブにコンパイルされた T-SQL モジュールとテーブル型を使ってこれらの列に対する操作を実行できるようになっています。However, starting SQL Server 2016 (13.x)SQL Server 2016 (13.x) and in Azure SQL Database it is now possible to create a memory-optimized table with multiple large columns (e.g., multiple varbinary(8000) columns) and LOB columns (i.e., varbinary(max), varchar(max), and nvarchar(max)) and perform operations on them using natively compiled T-SQL modules and table types.

行サイズの上限である 8060 バイトを超える列は、行外の、個別の内部テーブルに配置されます。Columns that do not fit in the 8060 byte row size limit are placed off-row, in a separate internal table. 行外の列ごとに対応する内部テーブルがあり、 それぞれの内部テーブルには非クラスター化インデックスが 1 つ含まれます。Each off-row column has a corresponding internal table, which in turn has a single nonclustered index. 行外の列に使用されるこれらの内部テーブルについて詳しくは、「sys.memory_optimized_tables_internal_attributes (Transact-SQL)」をご覧ください。For details about these internal tables used for off-row columns see sys.memory_optimized_tables_internal_attributes (Transact-SQL).

行とテーブルのサイズを計算するとことが役に立つシナリオがあります。There are certain scenarios where it is useful to compute the size of the row and the table:

  • テーブルが使用するメモリの量How much memory does a table use?

    • テーブルで使用されるメモリの量は、正確に計算することはできません。The amount of memory used by the table cannot be calculated exactly. 使用されるメモリの量には、多くの要因が影響します。Many factors affect the amount of memory used. たとえば、ページ単位のメモリ割り当て、局所性、キャッシュ、余白などの要因です。Factors such as page-based memory allocation, locality, caching, and padding. また、アクティブなトランザクションが関連付けられている行や、ガベージ コレクションを待機している行には複数のバージョンが存在します。Also, multiple versions of rows that either have active transactions associated or that are waiting for garbage collection.

    • テーブル内のデータとインデックスに必要な最小サイズは、後で説明する [テーブル サイズ] (table size) の計算によって得られます。The minimum size required for the data and indexes in the table is given by the calculation for [table size], discussed below.

    • メモリ使用量の計算で得られる値は、最善でも近似値です。配置プランにキャパシティ プランニングを含めることをお勧めします。Calculating memory use is at best an approximation and you are advised to include capacity planning in your deployment plans.

  • 行のデータ サイズと、そのデータ サイズが行サイズの上限である 8,060 バイト以下であるかどうか。The data size of a row, and does it fit in the 8,060 byte row size limitation? これを調べるには、以降に説明する行本文サイズ (row body size) の計算を使用します。To answer these questions, use the computation for [row body size], discussed below.

メモリ最適化テーブルは、行のコレクションと、行へのポインターを格納するインデックスで構成されています。A memory-optimized table consists of a collection of rows and indexes that contain pointers to rows. 次の図は、インデックスと行を含むテーブルを示しています。行には行ヘッダーと行本文が含まれています。The following figure illustrates a table with indexes and rows, which in turn have row headers and bodies:

メモリ最適化テーブル。Memory optimized table.
インデックスと行で構成されたメモリ最適化テーブル。Memory-optimized table, consisting of indexes and rows.

テーブル サイズの計算Computing Table Size

テーブルのメモリ内サイズ (バイト単位) は、次のように計算されます。The in-memory size of a table, in bytes, is computed as follows:

[table size] = [size of index 1] + ... + [size of index n] + ([row size] * [row count])  

ハッシュ インデックスのサイズはテーブルの作成時に固定され、実際のバケット数によって決まります。The size of a hash index is fixed at table creation time and depends on the actual bucket count. インデックス指定のときに指定された bucket_count は、最も近い 2 のべき乗となるように切り上げられ、これが実際のバケット数となります。The bucket_count specified with the index definition is rounded up to the nearest power of 2 to obtain the actual bucket count. たとえば、指定された bucket_count が 100,000 の場合、インデックスの実際のバケット数は 131,072 です。For example, if the specified bucket_count is 100000, the actual bucket count for the index is 131072.

[hash index size] = 8 * [actual bucket count]  

非クラスター化インデックスのサイズは [row count] * [index key size]と同程度です。The size of a nonclustered index is in the order of [row count] * [index key size].

行サイズは、ヘッダーと本文のサイズを合計して算出されます。The row size is computed by adding the header and the body:

[row size] = [row header size] + [actual row body size]  
[row header size] = 24 + 8 * [number of indexes]  

行本文サイズの計算Computing Row Body Size

行構造 メモリ最適化テーブルの行は、次のコンポーネントを備えています。Row Structure The rows in a memory-optimized table have the following components:

  • 行ヘッダーは、行のバージョン管理を実装するために必要なタイムスタンプを格納したものです。The row header contains the timestamp necessary to implement row versioning. 行ヘッダーにはほかにも、(上で説明した) ハッシュ バケットの行のチェーン関係を実装するためのインデックス ポインターが格納されています。The row header also contains the index pointer to implement the row chaining in the hash buckets (described above).

  • 行の本文は、実際の列データを格納する部分であり、NULL 値を許容する列の null 配列や可変長データ型のオフセット配列など、補助的な情報が含まれます。The row body contains the actual column data, which includes some auxiliary information like the null array for nullable columns and the offset array for variable-length data types.

次の図は、2 種類のインデックスを備えたテーブルの行構造を示したものです。The following figure illustrates the row structure for a table that has two indexes:

2 つのインデックスがあるテーブルの行構造。Row structure for a table that has two indexes.

開始タイムスタンプおよび終了タイムスタンプは、特定の行バージョンが有効である期間を示します。The begin and end timestamps indicate the period in which a particular row version is valid. この間隔で開始されるトランザクションで、この行バージョンが使用されることがあります。Transactions that start in this interval can see this row version. 詳細については、「 Transactions with Memory-Optimized Tables」(メモリ最適化テーブルでのトランザクション) を参照してください。For more details see Transactions with Memory-Optimized Tables.

インデックス ポインターは、ハッシュ バケットに属しているチェーン内の次の行を参照します。The index pointers point to the next row in the chain belonging to the hash bucket. 次の図は、(名前と都市の) 2 列があり、名前の列用と都市の列用にそれぞれ 1 つのインデックスを備えたテーブルの構造を示しています。The following figure illustrates the structure of a table with two columns (name, city), and with two indexes, one on the column name, and one on the column city.

2 つの列とインデックスを持つテーブルの構造。Structure of a table with two columns and indexes.

この図では、John と Jane の名前がハッシュされ、最初のバケットに格納されます。In this figure, the names John and Jane are hashed to the first bucket. Susan は、ハッシュされて 2 番目のバケットに格納されます。Susan is hashed to the second bucket. Beijing と Bogota の各都市は、ハッシュされて最初のバケットに格納されます。The cities Beijing and Bogota are hashed to the first bucket. Paris と Prague は、ハッシュされて 2 番目のバケットに格納されます。Paris and Prague are hashed to the second bucket.

以上のことから、名前のハッシュ インデックスのチェーンは次のようになります。Thus, the chains for the hash index on name are as follows:

  • 最初のバケット: (John, Beijing); (John, Paris); (Jane, Prague)First bucket: (John, Beijing); (John, Paris); (Jane, Prague)

  • 2 番目のバケット: (Susan, Bogota)Second bucket: (Susan, Bogota)

都市のインデックスのチェーンは次のようになります。The chains for the index on city are as follows:

  • 最初のバケット: (John, Beijing); (John, Paris)First bucket: (John, Beijing), (Susan, Bogota)

  • 2 番目のバケット: (John, Paris), (Jane, Prague)Second bucket: (John, Paris), (Jane, Prague)

終了タイムスタンプの ∞ (無制限) は、これが現在有効になっている行バージョンであることを示します。An end timestamp ∞ (infinity) indicates that this is the currently valid version of the row. この行は、この行バージョンが書き込まれてから更新および削除されていません。The row has not been updated or deleted since this row version was written.

時間が 200 より大きくなると、テーブルには次の行が含まれます。For a time greater than 200, the table contains the following rows:

[オブジェクト名]Name CityCity
JohnJohn BeijingBeijing
JaneJane PraguePrague

ただし、開始時刻が 100 のアクティブなトランザクションでは、以下のバージョンのテーブルが表示されます。However, any active transaction with begin time 100 will see the following version of the table:

[オブジェクト名]Name CityCity
JohnJohn ParisParis
JaneJane PraguePrague
SusanSusan BogataBogata

行本文サイズ (row body size) の計算について、次の表で説明します。The calculation of [row body size] is discussed in the following table.

行本文サイズには、計算されたサイズと実際のサイズという 2 種類の計算があります。There are two different computations for row body size: computed size and the actual size:

  • 計算されたサイズ (計算された行本体サイズ) の用途は、行サイズの上限 (8,060 バイト) を超えているかどうかを判断することです。The computed size, denoted with computed row body size, is used to determine if the row size limitation of 8,060 bytes is exceeded.

  • 実際のサイズ (実際の行本体サイズ) は、行本体がメモリ内およびチェックポイント ファイル内に格納されるときの実際のサイズです。The actual size, denoted with actual row body size, is the actual storage size of the row body in memory and in the checkpoint files.

計算された行本体サイズ実際の行本体サイズ の計算方法は似ています。Both computed row body size and actual row body size are calculated similarly. 次の表の最後に説明されているとおり、唯一の違いは、(n)varchar(i) 列と varbinary(i) 列のサイズの計算です。The only difference is the calculation of the size of (n)varchar(i) and varbinary(i) columns, as reflected at the bottom of the following table. 計算された行本体サイズでは、宣言されたサイズ i を列のサイズとして使用しますが、実際の行本体サイズではデータの実際のサイズを使用します。The computed row body size uses the declared size i as the size of the column, while the actual row body size uses the actual size of the data.

実際の行本文サイズ = SUM(シャロー型のサイズ) + 2 + 2 * ディープ型の列の数として指定した場合、行本文サイズの計算について、次の表で説明します。The following table describes the calculation of the row body size, given as actual row body size = SUM(size of shallow types) + 2 + 2 * number of deep type columns.

セクションSection サイズSize コメントComments
シャロー型の列Shallow type columns SUM([シャロー型のサイズ])。SUM([size of shallow types]). 個々の型のサイズは次のとおりです (バイト単位)。Size in bytes of the individual types is as follows:

Bit: 1Bit: 1

Tinyint: 1Tinyint: 1

Smallint: 2Smallint: 2

Int: 4Int: 4

Real: 4Real: 4

Smalldatetime: 4Smalldatetime: 4

Smallmoney: 4Smallmoney: 4

Bigint: 8Bigint: 8

Datetime: 8Datetime: 8

Datetime2: 8Datetime2: 8

Float: 8Float: 8

Money: 8Money: 8

Numeric (精度 <=18): 8Numeric (precision <=18): 8

Time: 8Time: 8

Numeric(精度>18): 16Numeric(precision>18): 16

Uniqueidentifier: 16Uniqueidentifier: 16
シャロー列の余白Shallow column padding 有効な値は次のとおりです。Possible values are:

ディープ型の列が存在し、シャロー列の合計データ サイズが奇数になる場合は 1。1 if there are deep type columns and the total data size of the shallow columns is as odd number.

それ以外の場合は、0。0 otherwise
ディープ型は、(var)binary 型と (n)(var)char 型です。Deep types are the types (var)binary and (n)(var)char.
ディープ型の列のオフセット配列Offset array for deep type columns 有効な値は次のとおりです。Possible values are:

ディープ型の列がない場合は 00 if there are no deep type columns

それ以外の場合は 2 + 2 * [ディープ型の列の数] (number of deep type columns)2 + 2 * [number of deep type columns] otherwise
ディープ型は、(var)binary 型と (n)(var)char 型です。Deep types are the types (var)binary and (n)(var)char.
NULL 配列NULL array [NULL 値を許容する列の数] / 8 (完全なバイト数になるように切り上げ)。[number of nullable columns] / 8, rounded up to full bytes. 配列は、NULL 値を許容する列ごとに 1 ビットを保持します。The array has one bit per nullable column. これは、完全なバイト数になるように切り上げられます。This is rounded up to full bytes.
NULL 配列の余白NULL array padding 有効な値は次のとおりです。Possible values are:

ディープ型の列が存在し、NULL 配列のサイズのバイト数が奇数である場合は 1。1 if there are deep type columns and the size of the NULL array is an odd number of bytes.

それ以外の場合は、0。0 otherwise
ディープ型は、(var)binary 型と (n)(var)char 型です。Deep types are the types (var)binary and (n)(var)char.
余白Padding ディープ型の列がない場合は 0If there are no deep type columns: 0

ディープ型の列がある場合、シャロー列に必要な最大の配置に基づいて、余白の 0 ~ 7 バイトが追加されます。If there are deep type columns, 0-7 bytes of padding is added, based on the largest alignment required by a shallow column. 前に説明したように、各シャロー列の配置は、列のサイズと等しい値にする必要があります。ただし、例外として、GUID 列の配置は 1 バイト (16 ではない) とし、数値列の配置は常に 8 バイト (16 ではない) とする必要があります。Each shallow column requires alignment equal to its size as documented above, except that GUID columns need alignment of 1 byte (not 16) and numeric columns always need alignment of 8 bytes (never 16). すべてのシャロー列間で必要となる配置の値の中で、最も大きな値が使用されます。それまでの合計サイズ (ディープ型の列を含まない) が必要な配置の倍数になるように、余白として 0 ~ 7 バイトが追加されます。The largest alignment requirement among all shallow columns is used, and 0-7 bytes of padding is added in such a way that the total size so far (without the deep type columns) is a multiple of the required alignment.
ディープ型は、(var)binary 型と (n)(var)char 型です。Deep types are the types (var)binary and (n)(var)char.
固定長のディープ型の列Fixed-length deep type columns SUM(固定長のディープ型の列のサイズ)SUM(size of fixed length deep type columns)

個々の列のサイズは次のとおりです。The size of each column is as follows:

char(i) および binary(i) の場合は i。i for char(i) and binary(i).

nchar(i) の場合は 2 * i。2 * i for nchar(i)
固定長のディープ型の列では、列の型が char(i)、nchar(i)、または binary(i) です。Fixed-length deep type columns are columns of type char(i), nchar(i), or binary(i).
可変長のディープ型の列の計算されたサイズVariable length deep type columns computed size SUM(可変長のディープ型の列の計算されたサイズ)SUM(computed size of variable length deep type columns)

個々の列の計算されたサイズは次のとおりです。The computed size of each column is as follows:

varchar(i) および varbinary(i) の場合は i。i for varchar(i) and varbinary(i)

nvarchar(i) の場合は 2 * i。2 * i for nvarchar(i)
この行が適用されるのは 計算された行本体サイズ のみです。This row only applied to computed row body size.

可変長のディープ型の列では、列の型が varchar(i)、nvarchar(i)、または varbinary(i) です。Variable-length deep type columns are columns of type varchar(i), nvarchar(i), or varbinary(i). 計算されたサイズは、列の最大長 (i) で決まります。The computed size is determined by the max length (i) of the column.
可変長のディープ型の列の実際のサイズVariable length deep type columns actual size SUM(可変長のディープ型の列の実際のサイズ)SUM(actual size of variable length deep type columns)

個々の列の実際のサイズは次のとおりです。The actual size of each column is as follows:

varchar(i) の場合は n (ここで n は列に格納されている文字数)。n, where n is the number of characters stored in the column, for varchar(i).

nvarchar(i) の場合は 2 * n (ここで n は列に格納されている文字数)。2 * n, where n is the number of characters stored in the column, for nvarchar(i).

varbinary(i) の場合は n (ここで n は列に格納されているバイト数)。n, where n is the number of bytes stored in the column, for varbinary(i).
この行が適用されるのは 実際の行本体サイズ のみです。This row only applied to actual row body size.

実際のサイズは、行の列内に格納されているデータで決まります。The actual size is determined by the data stored in the columns in the row.

例: テーブルと行のサイズの計算Example: Table and Row Size Computation

ハッシュ インデックスの場合、実際のバケット数は最も近い 2 のべき乗に切り上げられます。For hash indexes, the actual bucket count is rounded up to the nearest power of 2. たとえば、指定された bucket_count が 100,000 ならば、そのインデックスの実際のバケット数は 131,072 です。For example, if the specified bucket_count is 100000, the actual bucket count for the index is 131072.

次の定義を含む Orders テーブルがあるとします。Consider an Orders table with the following definition:

CREATE TABLE dbo.Orders (  
     OrderID int NOT NULL   
           PRIMARY KEY NONCLUSTERED,  
     CustomerID int NOT NULL   
           INDEX IX_CustomerID HASH WITH (BUCKET_COUNT=10000),  
     OrderDate datetime NOT NULL,  
     OrderDescription nvarchar(1000)  
) WITH (MEMORY_OPTIMIZED=ON)  
GO  

このテーブルには 1 つのハッシュ インデックスと 1 つの非クラスター化インデックス (主キー) が含まれていることを注意してください。Notice that this table has one hash index and a nonclustered index (the primary key). さらに、3 個の固定長列および 1 個の可変長列があり、そのうちの 1 個の列は NULL 値を許容します (OrderDescription)。It also has three fixed-length columns and one variable-length column, with one of the columns being NULLable (OrderDescription). Orders テーブルに 8,379 行が含まれ、OrderDescription 列の値の平均の長さが 78 文字であるとします。Let's assume the Orders table has 8379 rows, and the average length of the values in the OrderDescription column is 78 characters.

このテーブルのサイズを判断するには、最初にインデックスのサイズを調べます。To determine the table size, first determine the size of the indexes. 両方のインデックスの bucket_count は 10,000 と指定されています。The bucket_count for both indexes is specified as 10000. これは、最も近い 2 のべき乗 (16,384) に切り上げられます。This is rounded up to the nearest power of 2: 16384. したがって、Orders テーブルのインデックスの合計サイズは次のとおりです。Therefore, the total size of the indexes for the Orders table is:

8 * 16384 = 131072 bytes  

テーブルのデータ サイズは次のとおりです。What remains is the table data size, which is,

[row size] * [row count] = [row size] * 8379  

(このテーブルには 8,379 行あります。)次の計算式を使用します。(The example table has 8379 rows.) Now, we have:

[row size] = [row header size] + [actual row body size]  
[row header size] = 24 + 8 * [number of indices] = 24 + 8 * 1 = 32 bytes  

ここで、[実際の行本文サイズ]を計算します。Next, let's calculate [actual row body size]:

  • シャロー型の列:Shallow type columns:

    SUM([size of shallow types]) = 4 [int] + 4 [int] + 8 [datetime] = 16  
    
  • シャロー列のサイズが偶数であるため、シャロー列の余白は 0 です。Shallow column padding is 0, as the total shallow column size is even.

  • ディープ型の列のオフセット配列:Offset array for deep type columns:

    2 + 2 * [number of deep type columns] = 2 + 2 * 1 = 4  
    
  • NULL 配列は 1 です。NULL array = 1

  • NULL 配列のサイズが奇数であり、ディープ型の列が存在するため、null 配列の余白は 1 です。NULL array padding = 1, as the NULL array size is odd and there is a deep type column.

  • 余白Padding

    • 必要な配置のうち、最も大きな値は 8 です。8 is the largest alignment requirement.

    • これまでのサイズは、16+ 0 + 4 + 1 + 1 = 22 です。Size so far is 16 + 0 + 4 + 1 + 1 = 22.

    • 最も近い 8 の倍数は 24 です。Nearest multiple of 8 is 24.

    • 合計余白は 24 - 22 = 2 バイトです。Total padding is 24 - 22 = 2 bytes.

  • 固定長のディープ型の列はありません (固定長のディープ型の列は 0)。There are no fixed-length deep type columns (Fixed-length deep type columns: 0.).

  • ディープ型の列の実際のサイズは 2 * 78 = 156 です。The actual size of deep type column is 2 * 78 = 156. 単一のディープ型の列である OrderDescriptionnvarchar 型です。The single deep type column OrderDescription has type nvarchar.

[actual row body size] = 24 + 156 = 180 bytes  

次のように計算を完了します。To complete the calculation:

[row size] = 32 + 180 = 212 bytes  
[table size] = 8 * 16384 + 212 * 8379 = 131072 + 1776348 = 1907420  

メモリ内のテーブルの合計サイズは、約 2 MB です。Total table size in memory is thus approximately 2 megabytes. ただし、メモリ割り当てによって発生する潜在的なオーバーヘッドや、このテーブルにアクセスするトランザクションに必要な行のバージョン管理は考慮されていません。This does not account for potential overhead incurred by memory allocation as well as any row versioning required for the transactions accessing this table.

実際にこのテーブルおよびインデックスに割り当てられ、使用されるメモリは、次のクエリを使用して取得することができます。The actual memory allocated for and used by this table and its indexes can be obtained through the following query:

select * from sys.dm_db_xtp_table_memory_stats  
where object_id = object_id('dbo.Orders')  

行外列の制限事項Off-row Column Limitations

メモリ最適化テーブルでの行外列の使用に固有の制限事項と注意事項を以下に示します。Certain limitations and caveats to using off-row columns in a memory-optimized table are listed below:

  • メモリ最適化テーブルに列ストア インデックスがある場合は、すべての列が行内に収まる必要があります。If there is a columnstore index on a memory-optimized table, then all the columns must fit in-row.
  • すべてのインデックス キー列が、行内に格納される必要があります。All index key columns must be stored in-row. インデックス キー列が行内に収まらない場合、インデックスの追加は失敗します。If an index key column doesn't fit in-row, adding the index fails.
  • 行外列を含むメモリ最適化テーブルの変更に関する注意事項。Caveats on altering a memory-optimized table with off-row columns.
  • LOB の場合、ディスク ベース テーブルのサイズ制限が反映されます (LOB 値に対する 2 GB の制限)。For LOBs the size limitation mirrors that of disk based tables (2GB limit on LOB values).
  • パフォーマンスを最適化するには、ほとんどの列を 8,060 バイトに収まるようにすることをお勧めします。For optimal performance, it is recommended to have most columns fit within 8060 bytes.

詳しくは、「What's new for In-Memory OLTP in SQL Server 2016 since CTP3」(CTP3 以降の SQL Server 2016 でのメモリ内 OLTP に関する新機能) ブログ投稿をご覧ください。What's new for In-Memory OLTP in SQL Server 2016 since CTP3 blog post further details some of these intricacies.

参照See Also

メモリ最適化テーブルMemory-Optimized Tables