postgresqlのbyteaカラム参照でOutOfMemoryエラーがでたときの原因と対処法
2023/11/25
OracleからPostgreSQLへマイグレーションした時に、BLobとbytea型のjavaヒープメモリの使い方の違いでoutOfMemoryエラーとなり苦戦したので原因と対処法のメモとなります。javaでpostgreSQLのbytea型を扱うときの話になり、jdbcの作りに依存した話となります。
OracleのBlob型をPostgreSQLで扱う場合byteaという型のカラムで扱う
OracleのBlob型はPostgreSQLではbytea型で扱います。Oracleと異なり最大1GBまでなどの制約があります。
一応、PostgreSQLでもラージオブジェクトがあり、1GB以上のサイズも扱えますが、こちらはラージオブジェクト用のAPIを利用してアクセスするため、通常のテーブルとは使い勝手が異なりますので、OracleのBlobはPostgreSQLではbyteaにマイグレーションします。
PostgreSQLのbyteaカラムは取得するとメモリ上に保持される
OracleのBlob型はselectでレコードを取得しても、バイナリデータへの参照しか保持しないため、メモリをそれほど消費しません。
しかし、PostgreSQLのbyteaカラムの場合は、selectで取得するとメモリ上にバイナリデータを保持します。
そのため、byteaカラムを含むレコードを複数行selectで取得してループを回して処理したりするときに、取得したレコード数のバイナリデータ分のヒープメモリを消費するため、簡単にOutOfMemoryとなり異常終了してしまいます。
OracleのBlobとPostgreSQLのbyteaでは、メモリの利用方法に互換性がないということになりますので注意が必要です。
対処方法
原因は複数レコードのbyteaカラムを一気に取得してしまっているからになります。
通常複数レコード取得するときはbyteaカラム本体は必要ないことが大半だと思いますので、このときのループ用の複数レコード取得のselectからbyteaカラムを削除します。
それをループ処理し、ループ内で毎回そのレコードをbyteaカラムを含めてピンポイントで1レコードだけ取得するようにすれば、ヒープメモリの使用量は1レコード分になるため解消します。