首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >绑定参数慢,JdbcTemplate甚至慢

绑定参数慢,JdbcTemplate甚至慢
EN

Stack Overflow用户
提问于 2016-06-13 07:53:27
回答 1查看 2.2K关注 0票数 5

我的Oracle 11g数据库中有一个四列表,实现了扩展表反模式。我注意到有些查询花了很长时间,并努力创建更好的索引;在交互会话中,它很好,但使用Spring的NamedJdbcTemplate仍然很慢。

考虑以下例程:

代码语言:javascript
复制
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));
}

以下是结果。确切的时间因跑步而异,但总是保持在相同的数量级。

  1. 在没有任何绑定参数的情况下,使用查询的速度非常快,顺序小于100 ms。
  2. 使用带有9个绑定变量的Spring的JdbcTemplate,性能会下降到爬行,时间大约为4秒。
  3. 最后,使用NamedJdbcTemplate (最简单、最灵活)与案例2一样慢;这至少不足为奇,因为在窗帘后面,NamedJdbcTemplate将用命名的参数替换我的查询,使之与案例2类似。

它没有得到连接,因为它们都是从同一个连接池中获取的。它似乎并不仅仅是queryForRowSet()函数,因为这实际上也是在最快的情况下使用的。同样,看起来与Spring的异常翻译或参与正在进行的事务无关,因为这也会影响案例1。

最后,问题是:与没有绑定参数的普通语句相比,为什么带有绑定参数的Spring的JdbcTemplate在这种情况下非常慢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-28 14:15:01

事实证明,这既不是JdbcTemplate也不是NamedJdbcTemplate。它也不是关于PreparedStatementStatement,即使后者是最快的。这只是因为没有绑定参数的普通语句。如果我有没有绑定参数的查询,那么对于原始的JDBC和NamedJdbcTemplate,它的速度差不多。

我们的Oracle 11g简单地为这个查询选择了一个糟糕的执行计划,包含9个绑定参数,并且不管实际参数是什么,都坚持执行它。我不知道为什么,也没有真正的DBA可用。

在使用相同数据的PostgreSQL 9.3数据库上进行的测试表明,无论使用绑定参数还是不绑定参数,它都是同样快的;同时还安装了开箱即用的Ubuntu。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37784388

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档