我有四列的表在實施擴展表反模式我的Oracle 11g數據庫。我注意到一些查詢耗時很長,並努力創建更好的索引;在交互式會話中很好,但使用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。
所以最後的問題是:爲什麼Spring的JdbcTemplate
使用綁定參數,從而在這種情況下很慢相對於沒有綁定參數普通聲明?
你要點的鏈接導致404後的代碼**的問題itselff **。 –
代碼是_long_。你真的想要這個問題嗎?無論如何,我修復了斷開的鏈接,對此抱歉。 –
是的,它應該在問題中。這是這裏的規則。我們希望您的問題及其答案在兩年內仍然可以理解,當您的要求不存在或已被修改時。 –