100億のレコードテーブルがあるので、スペースの割り当てを改善する必要があります。私のテーブルには、浮動小数点型(単精度)のフィールドしかありません。 NUMBER
またはBINARY_FLOAT
または他の何かの最良の選択は何ですか?
それはあなたのデータに依存します(そしてこれはあなたが2つのデータ型の異なる振る舞いを気にしないことを前提としています)。実際に保存しているものと同様のサンプルデータを使用してテストをまとめ、使用するスペースが少ないアプローチを見つけることができます。
2つの異なる列を持つテーブルnum_test
を作成します。1つはnumber
として宣言され、もう1つはbinary_float
として宣言されます。
create table num_test (
num_col number,
flt_col binary_float
);
0.001刻みで100,000行のデータを入力すると
begin
for i in 1 .. 100000
loop
insert into num_test( num_col, flt_col )
values( i/1000, i/1000 );
end loop;
end;
次に、値を格納するために必要な最小、最大、および平均のサイズを確認できます
select min( vsize(num_col) ), max( vsize(num_col) ), avg( vsize(num_col) ),
min( vsize(flt_col) ), max( vsize(flt_col) ), avg( vsize(flt_col) )
from num_test;
これを実行すると、数値列の平均が1行あたり3.89バイト(最小2、最大4)であるのに対し、binary_float
ごとに4バイトのストレージが必要であることがわかります。したがって、この場合、number
を使用することでわずかな節約ができます。
しかし、それが全体の話ですか?いいえ。異なるサンプルデータを使用すると、非常に異なる結果が得られます。同じテストを実行しますが、すべてを3で割ります
begin
for i in 1 .. 100000
loop
insert into num_test( num_col, flt_col )
values( i/1000/3, i/1000/3 );
end loop;
end;
ここで、同じvsize
クエリを実行すると、number
列が最大21バイトのストレージを使用し、200,000行で平均7.69バイトになることがわかります。 flt_col
は、すべての行に固定の4バイトを使用しています。
データによっては、どちらかのアプローチがより多くのスペースを使用する場合があります。もちろん、スペース使用率に大きな違いがある場合、浮動小数点数に移動すると、より大きな丸めの問題が発生する可能性があります。
結果はバージョンに依存する可能性があることにも注意してください。私は11.2データベースでテストを行いました。ドキュメントには、 binary_float
は常に4バイトのストレージを使用します と記載されています。 10.2では、ドキュメントには binary_float
は余分な長さインジケーターが含まれているため5バイトかかった と示されています。 32ビット値に長さバイトが必要な理由は私にはわかりません。そのため、以前のバージョンのOracleで5番目のバイトが必要だった理由を理解するのは難しいですが、ドキュメントには一貫性があります。
INDEX
で使用されるスペースも必要になる可能性があるため、TABLE およびINDEXで使用されるスペースを計算するには、次のステートメントを実行できます。
SELECT T, table_name, sum(bytes) as sum_bytes FROM
(
SELECT 'TABLE' as T, segment_name table_name, owner, bytes
FROM dba_segments WHERE segment_type = 'TABLE'
)
WHERE owner in UPPER('&owner')
GROUP BY T, table_name, owner
HAVING SUM(bytes) > 100000
UNION ALL
SELECT T, table_name, sum(bytes) as sum_bytes FROM
(
SELECT 'INDEX' as T, i.table_name, i.owner, s.bytes
FROM dba_indexes i, dba_segments s
WHERE s.segment_name = i.index_name AND s.owner = i.owner AND s.segment_type = 'INDEX'
)
WHERE owner in UPPER('&owner')
GROUP BY T, table_name, owner
HAVING SUM(bytes) > 100000;