PostgreSQL JDBC Driverを使ってクエリを投げる際に過去にハマった点をメモしておきます。
PreparedStatementの性能傾向が変わる?
PreparedStatementオブジェクトを作ってクエリを繰り返し実行していると、ある時点から急にクエリ性能が良くなる場合があります。
これは、PostgreSQL JDBC Driverの仕様で、一定回数以上同じPreparedStatementオブジェクトでクエリ実行を繰り返すと、PostgreSQLサーバ側にクエリがキャッシュされてさらに高速化されるためです。
つまり、PostgreSQL JDBC Driverを使っている場合、PreparedStatementによるクエリ実行の最適化には2段階あって
- クライアント側の最適化
- クライアント側 + PostgreSQLサーバ側の最適化
となっています。
特に、PostgreSQLサーバ側の最適化の影響が大きく、これによりSQL文のパースや実行計画作成がスキップされるため、2.の段階になった瞬間に性能が向上しやすくなります。
で、1.から2.にグレードアップするのがデフォルト設定では5回目からです。このしきい値は変更可能です。
- PostgreSQLの接続URLにてパラメータ
prepareThreshold = int
で指定する。クエリ全体に影響。 - PreparedStatementオブジェクトごとに
void setPrepareThreshold(int threshold)
メソッドで指定する。
詳細は、ドキュメント参照のこと。
https://jdbc.postgresql.org/documentation/head/server-prepare.html
https://jdbc.postgresql.org/documentation/head/connect.html
PreparedStatementって?
ややこしいことにPostgreSQLサーバ側のクエリキャッシュ機構もPrepared statementと呼ばれています。
そのため、PostgreSQL → JDBCの順で勉強していると、
(JDBC APIの)PreparedStatementを使ってクエリを投げているのに(PostgreSQLの)Prepared Statement機能が使われていない( ;д;)...
というポルナレフ状態になります。
自分はこちらのハマり方をしました。。。
PostgreSQLのPrepared Statement機能もこれまた予想外の挙動をする時があってハマりやすいのですが、それはまた別途書きます。