インデックス容量見積

http://otndnld.oracle.co.jp/skillup/oracle9i/4_1/index.html

 

【1】見積手順

1. 1レコードの平均長を求める

[1レコードの平均長] = [レコードヘッダ] + [ROWID] + [オーバーヘッド] + Σ([列ヘッダ] + [列データ])

[レコードヘッダ] = 3バイト
[ROWID] = 6バイト
[オーバーヘッド] = (127バイト以下の列数 * 1) + (128バイト以上の列数 * 2) + 4 バイト ;一意でない索引の場合は1バイト加算

[列ヘッダ] = 対応する列のデータ長が250バイト以下(NULL含む)の場合は1バイト、251バイト以上の場合は3バイト

[列データ]
CHAR → テーブル定義の長さ
VARCHAR2 → 実際に格納されているデータの長さ
NUMBER → 1 + CEIL(n / 2) ; nは格納された数値の整数部・小数部を合わせた総桁数。n>38の場合は38
DATE → 7バイト
TIMESTAMP → 11バイト

2. 1ブロックに収まるレコード数を求める

[ブロックヘッダ] = 96 + 24 * [INITRANS]

[予備領域] = CEIL( ([ブロックサイズ] - [ブロックヘッダ]) * [PCTFREE])

[データ格納部] = [ブロックサイズ] - [ブロックヘッダ] - [予備領域]

[1ブロックに収まるレコード数] = TRUNC([データ格納部] / [1レコードの平均長])

3. インデックス容量算出


[インデックス容量] = CEIL( [レコード件数] * 1.05 / [1ブロックに収まるレコード数]) * [ブロックサイズ]

【2】計算例
前提:
下記デフォルト値を使用する
[ブロックサイズ] = 8192バイト
[INITRANS] = 2
[PCTFREE] = 10%

データ件数 = 100万件

対象テーブル定義:
create table tab1(col1 number(12,3),col2 varchar2(10),col3 date);
対象インデックス定義:
create index ind1 on tab1(col1,col2,col3);


[1レコードの平均長]= 3 + 6 + {(3*1) + (0*2) + 4 + 1} + {(1 + 9) + (1 + 10) + (1 + 7)} = 46
[ブロックヘッダ] = 96 + 24 * 2 = 144
[予備領域] = CEIL( (8192 - 144) * 0.1) = 805
[データ格納部] = 8192 - 144 - 805 = 7243
[1ブロックに収まるレコード数] = TRUNC(7243/46) = 157
[インデックス容量] = CEIL( 1000000 * 1.05 / 157 ) * 8192 = 54788096 ≒ 52 Mバイト

【3】実測値との比較

select sum(bytes/1024/1024) from user_segments where segment_name = 'IND1';

→ 37Mバイトとなりおよそ一致


【1】見積手順

1. 1レコードの平均長を求める

[1レコードの平均長] = [レコードヘッダ] + [可変長ヘッダ] + Σ([列ヘッダ] + [列データ])


[レコードヘッダ] = 5バイト
[可変長ヘッダ] = CEILING(N/8) ;NはNULLにすることができるカラム数

[列ヘッダ]
→ 0バイト ; 対応する列がNULL可変長フィールドや固定長フィールドの場合
→ 1バイト ; 対応する列が非NULL可変長でデータ長が127バイト以下の場合
→ 2バイト ; 対応する列が非NULL可変長でデータ長が128バイト以上の場合


[列データ]

CHAR(M) → 実バイト数
VARCHAR(M) → 文字数Mに対するバイト長Lが255以下の場合実バイト数+1、Lが256以上の場合実際のバイト数+2
INTEGER → 4バイト
DATE → 3バイト
DATETIME → 5 バイト + 小数秒ストレージ(0~3バイト)


2. 1ブロックに収まるレコード数を求める

[fillfactor] = 15/16
[データ格納部] = TRUNC([ブロックサイズ] * [fillfactor])

[1ブロックに収まるレコード数] = TRUNC([データ格納部] / [1レコードの平均長])

3. インデックス容量算出

[インデックス容量] = CEIL( [レコード件数] * 1.05 / [1ブロックに収まるレコード数]) * [ブロックサイズ]


【2】計算例
前提:
下記デフォルト値を使用する
[ブロックサイズ] = 16384バイト

データ件数 = 100万件

対象テーブル定義:
create table tab1(col1 int not null primary key,col2 varchar(10),col3 datetime);
対象インデックス定義:
create index ind1 on tab1(col3);


[1レコードの平均長] = 5 + 1 + {(1+4) + (0+5)} = 16
[データ格納部] = TRUNC( 16384 * 15/16 ) = 15360
[1ブロックに収まるレコード数] = TRUNC( 15360/16 ) = 960
[インデックス容量] = CEIL( 1000000 * 1.05 / 960 ) * 16384 = 17924096 = 17 Mバイト


【3】実測値との比較


SELECT
table_name, engine, table_rows AS tbl_rows,
avg_row_length AS rlen,
floor( (data_length+index_length)/1024/1024) AS allmb, #総容量
floor( (data_length)/1024/1024) AS dmb, #データ容量
floor( (index_length)/1024/1024) AS imb #インデックス容量
FROM
information_schema.tables
WHERE
table_schema = database()
AND
table_name = 'tab1'
;

→ 15Mバイトとなりおよそ一致

【1】見積手順

1. 1レコードの平均長を求める

[1レコードの平均長] = [タプルヘッダ] + [ラインポインタ] + Σ([列データ])

[タプルヘッダ] = 8バイト
[ラインポインタ] = 4バイト

[列データ]
char(n) → 文字数nに対するバイト長Nが125以下の場合N+1、126以上の場合N+4
varchar(n) → 文字数nに対するバイト長Nが125以下の場合実バイト数+1、126以上の場合実バイト数+4
integer → 4バイト
date → 4バイト
timestamp → 8バイト


2. 1ブロックに収まるレコード数を求める

[ページヘッダ] = 24バイト
[SpecialSpace] = 16バイト

[データ格納部] = TRUNC([ブロックサイズ] * [fillfactor] - [ページヘッダ] - [SpecialSpace])

[1ブロックに収まるレコード数] = TRUNC([データ格納部] / [1レコードの平均長])

3. インデックス容量算出


[インデックス容量] = CEIL( [レコード件数] * 1.05 / [1ブロックに収まるレコード数]) * [ブロックサイズ]


【2】計算例
前提:
下記デフォルト値を使用する
[ブロックサイズ] = 8192バイト
[fillfactor] = 90%

データ件数 = 100万件

対象テーブル定義:
create table tab1(col1 integer,col2 varchar(10),col3 timestamp);
対象インデックス定義:
create index ind1 on tab1(col1,col2,col3);


[1レコードの平均長]= 8 + 4 + (4 + 10+1 + 8) = 35
[データ格納部] = TRUNC(8192 * 0.9 - 24 - 16) = 7332
[1ブロックに収まるレコード数] = TRUNC(7332/35) = 209
[インデックス容量] = CEIL( 1000000 * 1.05 /209 ) * 8192 = 41156608 ≒ 39 Mバイト


【3】実測値との比較

 

SELECT pg_size_pretty(pg_relation_size('ind1'));

→ 39Mバイトとなりおよそ一致


https://docs.microsoft.com/ja-jp/sql/relational-databases/databases/estimate-the-size-of-a-nonclustered-index?view=sql-server-ver15

【1】見積手順

1. 1レコードの平均長を求める

[1レコードの平均長] = [レコードヘッダ] + [NULLビットマップ] + [可変長列追跡] + Σ([列データ])

[レコードヘッダ] = 1バイト
[NULLビットマップ] = TRUNC( 2 + ( ( 列総数 + 7) / 8) )
[可変長列追跡] = 2 + ( 可変長列の数 * 2)

[列データ]
char(n) → n
varchar(n) → n+2
int → 4バイト
date → 3バイト
datetime2 → 9バイト

※非ユニークインデックスの場合、データ行ロケーターをインデックス構成列にみなし追加
→列総数と可変長列の数が1増える。列データが8バイト増える。

2. 1ブロックに収まるレコード数を求める


[ページヘッダ] = 96

[予備領域] = CEIL( ([ブロックサイズ] - [ページヘッダ]) * (100 - [Fill_Factor]) / 100)

[データ格納部] = [ブロックサイズ] - [ページヘッダ] - [予備領域]

[1ブロックに収まるレコード数] = TRUNC([データ格納部] / ( [1レコードの平均長] + 2) )

3. インデックス容量算出


[インデックス容量] = CEIL( [レコード件数] * 1.05 / [1ブロックに収まるレコード数]) * [ブロックサイズ]


【2】計算例
前提:
下記デフォルト値を使用する
[ブロックサイズ] = 8192バイト
[Fill_Factor] = 100%

データ件数 = 100万件
テーブルタイプ = ヒープ

対象テーブル定義:
create table tab1(col1 int,col2 varchar(10),col3 datetime2);
対象インデックス定義:
create index ind1 on tab1(col3);


[1レコードの平均長]= 1 + 3 + { 2 + (1 * 2) } + { 9 + 8 } = 25
[予備領域] = 0
[データ格納部] = 8192 - 96 - 0 = 8096

[1ブロックに収まるレコード数] = TRUNC(8096/(25 + 2)) = 299

[インデックス容量] = CEIL( 1000000 * 1.05 /299 ) * 8192 = 28770304 ≒ 27 Mバイト


【3】実測値との比較

EXEC sp_spaceused 'dbo.tab1';
go

→ 21Mバイトとなりおよそ一致