と私は拡張テーブルアンチパターンを実装する私のOracle 11gデータベースに4列のテーブルを持っています。私はいくつかのクエリが非常に長くかかることに気付き、より良いインデックスを作成しようと努力しました。インタラクティブセッションではうまくいっていましたが、SpringのNamedJdbcTemplate
を使ってもまだ遅いです。、さらに遅いJdbcTemplate
には、以下のルーチンを考えてみましょう。
private void getObjectIds(ObjectDomain domain, HashMap<String, List<String>> dimensionMap)
throws SQLException {
String sql = "SELECT m2.OBJECT_ID"
+ " FROM MetaInformations m1, MetaInformations m2\n"
+ " WHERE m1.OBJECT_ID = m2.OBJECT_ID\n"
+ " AND m1.OBJECT_DOMAIN = :domain AND m1.KEY = :key1 AND\n"
+ " m1.REF_OBJ_VALUE IN (:values1)\n"
+ " AND m2.OBJECT_DOMAIN = :domain AND m2.KEY = :key2 AND\n"
+ " m2.REF_OBJ_VALUE IN (:values2)";
String sqlWithBind = "SELECT m2.OBJECT_ID\n"
+ " FROM MetaInformations m1, MetaInformations m2\n"
+ " WHERE m1.OBJECT_ID = m2.OBJECT_ID\n"
+ " AND m1.OBJECT_DOMAIN = ? AND m1.KEY = ? AND\n"
+ " m1.REF_OBJ_VALUE IN (?, ?, ?, ?)\n"
+ " AND m2.OBJECT_DOMAIN = ? AND m2.KEY = ? AND\n"
+ " m2.REF_OBJ_VALUE IN (?)";
// Prebuilding statement, no bind variables left
Stopwatch stopWatch2 = Stopwatch.createStarted();
Iterator<Entry<String, List<String>>> entries = dimensionMap.entrySet().iterator();
Entry<String, List<String>> entry1 = entries.next();
Entry<String, List<String>> entry2 = entries.next();
String prebuilt = sql.replace(":domain", "'" + domain + "'")
.replace(":key1", "'" + entry1.getKey() + "'")
.replace(":values1",
entry1.getValue().stream().map(s -> "'" + s + "'").collect(Collectors.joining(", ")))
.replace(":key2", "'" + entry2.getKey() + "'")
.replace(":values2",
entry2.getValue().stream().map(s -> "'" + s + "'").collect(Collectors.joining(", ")));
Set<Long> rs2 = extractIdSet(getNamedParameterJdbcTemplate().queryForRowSet(prebuilt, Collections.emptyMap()));
log.warn("Prebuilt took: {} ms", stopWatch2.elapsed(TimeUnit.MILLISECONDS));
// Simple JDBCTemplate with 9 bind parameters
Stopwatch stopWatch5 = Stopwatch.createStarted();
Set<Long> rs1 = extractIdSet(getJdbcTemplate().queryForRowSet(sqlWithBind,
domain.toString(),
entry1.getKey(),
entry1.getValue().get(0),
entry1.getValue().get(1),
entry1.getValue().get(2),
entry1.getValue().get(3),
domain.toString(),
entry2.getKey(),
entry2.getValue().get(0)));
log.warn("JdbcTemplate took: {} ms", stopWatch5.elapsed(TimeUnit.MILLISECONDS));
// Most beautiful: NamedJDBCTemplate
Stopwatch stopWatch3 = Stopwatch.createStarted();
Map<String, Object> paramMap = createNamedParameterMap(domain, dimensionMap);
Set<Long> rs3 = extractIdSet(getNamedParameterJdbcTemplate().queryForRowSet(sql, paramMap));
log.warn("NamedParameterJdbcTemplate took: {} ms", stopWatch3.elapsed(TimeUnit.MILLISECONDS));
}
は結果があります。正確なタイミングは実行ごとに異なりますが、常に同じオーダーの大きさにとどまっていました。任意のバインド・パラメータなしでクエリを使用して
- は100ms未満のために、非常に迅速に完了します。
- 9つのバインド変数を持つSpringの
JdbcTemplate
を使用すると、パフォーマンスはクロールに劣化し、約4秒となります。 - 最後に、最も簡単で柔軟性のある
NamedJdbcTemplate
、使用、ケース2と同じくらい遅いです。これは、少なくとも、カーテンの後ろ以来NamedJdbcTemplate
は、ケース2
と同等の何かそれらはすべて同じ接続プールからそれらを得るようそれは、接続を取得していないに名前付きパラメータと私のクエリを置き換えますは驚くに当たりません。実際には最も速いケースでも使用されるので、queryForRowSet()
関数だけではないようです。同じように、Spring 1の例外翻訳や進行中のトランザクションへの参加とは何の関係もないように見えます。これは、ケース1にも影響するはずです。
だから、最終的には、質問:なぜ春のJdbcTemplate
バインド・パラメータとは、バインド・パラメータのないプレーンな声明に比べて、この場合のように非常に遅いのですか?
あなたのgistリンクは404になります。コードは** itselff **の質問に投稿してください。 –
コードは_long_です。あなたは本当に質問にそれをしたいですか?とにかく、私は壊れたリンクを修正しました、残念です。 –
はい、それは質問の中にあるべきです。それがここのルールです。私たちはあなたの質問とその答えが、あなたの要点がもう存在しないか、または変更されている場合でも、2年間で理解できるようにします。 –