データ型による性能の違い

テストテーブル作成

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型のまま比較できるようにすれば性能があがるはず。