私のデータベースにはzip
、列を持つテーブルがありcode
ます。ユーザーは郵便番号のリストをアップロードできますが、データベースに既に存在するものを特定する必要があります。現在、次の Hibernate クエリ (HQL) を使用してこれを行っています。
select zip.code from Zip zip
where zip.code in (:zipCodes)
パラメータの値は:zipCodes
、ユーザーがアップロードしたコードのリストです。ただし、私が使用している Hibernate のバージョンには、このようなリスト パラメータのサイズを制限するバグがあり、場合によってはこの制限を超えています。
そのため、郵便番号の (非常に長い可能性がある) リストのどれが既にデータベースに存在するかを把握する別の方法を見つける必要があります。ここに私が検討したいくつかのオプションがあります
オプション A
HQL の代わりに SQL を使用してクエリを書き直します。これにより Hibernate のバグは回避されますが、チェックする必要のある郵便番号が 30,000 ある場合、パフォーマンスが大幅に低下すると思われます。
オプション B
郵便番号のリストを一連のサブリストに分割し、サブリストごとに個別のクエリを実行します。繰り返しますが、これにより Hibernate のバグは回避されますが、パフォーマンスは依然としてひどいものになる可能性があります。
オプション C
一時テーブルを使用します。つまり、チェックする郵便番号を一時テーブルに挿入し、それをテーブルに結合しzip
ます。このソリューションのクエリ部分はかなりうまく機能するはずですが、一時テーブルの作成と最大 30,000 行の挿入はそうではありません。しかし、おそらく私はそれを正しい方法で行っていません。疑似Javaコードで私が考えていたことは次のとおりです
/**
* Indicates which of the Zip codes are already in the database
*
* @param zipCodes the zip codes to check
* @return the codes that already exist in the database
* @throws IllegalArgumentException if the list is null or empty
*/
List<Zip> validateZipCodes(List<String> zipCodes) {
try {
// start transaction
// execute the following SQL
CREATE TEMPORARY TABLE zip_tmp
(code VARCHAR(255) NOT NULL)
ON COMMIT DELETE ROWS;
// create SQL string that will insert data into zip_tmp
StringBuilder insertSql = new StringBuilder()
for (String code : zipCodes) {
insertSql.append("INSERT INTO zip_tmp (code) VALUES (" + code + ");")
}
// execute insertSql to insert data into zip_tmp
// now run the following query and return the result
SELECT z.*
FROM zip z
JOIN zip_tmp zt ON z.code = zt.code
} finally {
// rollback transaction so that temporary table is removed to ensure
// that concurrent invocations of this method operate do not interfere
// with each other
}
}
上記の疑似コードよりも効率的な実装方法はありますか、それとも私が思いもよらなかった別の解決策がありますか? Postgres データベースを使用しています。