データ型による性能の違い
テストテーブル作成
create table int4_test(d int4); create table int8_test(d int8); create table float4_test(d float4); create table float8_test(d float8); create table numeric_test(d numeric); create table text_test(d text); create table varchar_test(d varchar); create table name_test(d name);
テストデータ作成
以下のスクリプトでランダムなデータを100万件作成した。
#!/usr/bin/perl my $i; for($i = 0; $i < 1000000; $i++) { printf("%.10d\n", rand 100); }
データ読み込み
copy int4_test from '/home2/ogawa/pg/test/testdata.txt';
(毎回tableをtruncateして5回実行した)
int4: 13.136s 12.827s 13.627s 12.809s 13.932s int8: 12.729s 12.773s 13.345s 12.768s 13.489s float4: 14.013s 14.978s 13.957s 15.014s 13.927s float8: 16.118s 14.192s 14.248s 14.437s 14.352s numeric: 14.058s 13.434s 14.418s 13.481s 15.201s text: 14.060s 15.370s 13.639s 15.252s 13.623s varchar: 15.263s 13.652s 16.440s 13.673s 14.869s name: 22.158s 20.085s 19.370s 21.588s 21.702s
検索
select count(*) from int4_test where d = '0000000011';
(5回実行した)
int4: 3.128s 1.503s 1.386s 1.404s 1.391s int8: 3.237s 1.523s 1.428s 1.429s 1.418s float4: 3.248s 1.571s 1.474s 1.474s 1.474s float8: 4.023s 1.649s 1.525s 1.517s 1.517s numeric: 4.513s 2.410s 2.299s 2.314s 2.272s text: 4.248s 2.115s 2.016s 2.013s 1.988s varchar: 4.368s 2.192s 2.071s 2.089s 2.065s name: 3.917s 2.139s 1.962s 1.967s 1.963s
2回目以降の実行は、キャッシュが効いて速くなっている。
結論
int4が最速。int8もそれほど悪くない。
numericは比較が遅い。
int4の比較について
int4の'='のテストはint4eq()で実行される。
int4eq(PG_FUNCTION_ARGS) { int32 arg1 = PG_GETARG_INT32(0); int32 arg2 = PG_GETARG_INT32(1); PG_RETURN_BOOL(arg1 == arg2); }
PostgreSQLのfunction特有のマクロがあって分かり難いが,やってることは以下のコードとほぼ同じである。
int inteq(int arg1, int arg2) { return (arg1 == arg2); }
numericの比較について
numericの'='のテストは,numeric_eqで実行される。
numeric_eqから以下のように多くの関数が実行され,pallocでメモリを確保したりmemcpyでデータをコピーしている。このためint4よりも実行コストが高い。
numeric_eq cmp_numerics init_var set_var_from_num alloc_var digitbuf_alloc palloc memcpy cmp_var cmp_abs free_var pfree
Numeric型からNumericVar型へ変換してから比較しているため,palloc, memcpyの実行が必要になっているが,Numeric型のまま比較できるようにすれば性能があがるはず。