libpq.dll

libpq.dllで検索SQLを実行して検索結果を取得するとき,getAnotherTuple()に負荷が集中する。
getAnotherTuple()の中で負荷が高い場所は,for (i = 0; i < nfields; i++)の中のpqGetInt(), pqResultAlloc(), pqGetnchar()。

pqGetInt()は,引数にバイト数(2 or 4)を渡すようになっており,pqGetInt()内部でswitch文で処理を分けているが,このバイト数はハードコーディングされているので,わざわざ実行時にswitchで分岐するのではなく、コンパイル時に解決してしまったほうがいい。
2byte用と4byte用の関数を用意して,それを実行する。2byte用はpqGetInt2(), 4byte用はpgGetInt4()とかにする。さらに、inline化したほうがいい。

backend側のlibpqも,pq_sendint()などでswitch()で処理を分けているが,これもbyte数ごとに別関数にしたほうが分岐が減っていいような気がする。
ただし、backend側はpq_sendint()より負荷が高い処理が多いので、得られる効果は少ない。

pqResultAlloc()は,PGRESULT_DATA_BLOCKSIZEで指定されている大きさのメモリブロックを確保して,PGresultのcurBlockに線形リストで管理する。
PGRESULT_DATA_BLOCKSIZEは2kbyteで定義されているが,大量のデータを取得するときは,2kbyteでは小さすぎで,mallocが頻繁に発生してしまう。
PQclearで線形リストのメモリを開放するが,この処理の負荷も高くなる。

PGRESULT_DATA_BLOCKSIZEを動的に設定する仕組みにできないか。
例えば、以下のような仕組み。
- カラム数に比例して,確保するブロックサイズを計算する
- mallocする度に,ブロックサイズを大きくする