Mic*_*fel 6 java oracle spring jdbc jdbctemplate
我的 Oracle 11g 数据库中有一个四列表,实现了扩展表反模式。我注意到有些查询花费了很长时间,并努力创建更好的索引;在交互式会话中效果很好,但使用 Spring\xe2\x80\x99s 仍然很慢NamedJdbcTemplate。
考虑以下例程:
\n\nprivate void getObjectIds(ObjectDomain domain, HashMap<String, List<String>> dimensionMap)\n throws SQLException {\nString sql = "SELECT m2.OBJECT_ID"\n + " FROM MetaInformations m1, MetaInformations m2\\n"\n + " WHERE m1.OBJECT_ID = m2.OBJECT_ID\\n"\n + " AND m1.OBJECT_DOMAIN = :domain AND m1.KEY = :key1 AND\\n"\n + " m1.REF_OBJ_VALUE IN (:values1)\\n"\n + " AND m2.OBJECT_DOMAIN = :domain AND m2.KEY = :key2 AND\\n"\n + " m2.REF_OBJ_VALUE IN (:values2)";\nString sqlWithBind = "SELECT m2.OBJECT_ID\\n"\n + " FROM MetaInformations m1, MetaInformations m2\\n"\n + " WHERE m1.OBJECT_ID = m2.OBJECT_ID\\n"\n + " AND m1.OBJECT_DOMAIN = ? AND m1.KEY = ? AND\\n"\n + " m1.REF_OBJ_VALUE IN (?, ?, ?, ?)\\n"\n + " AND m2.OBJECT_DOMAIN = ? AND m2.KEY = ? AND\\n"\n + " m2.REF_OBJ_VALUE IN (?)";\n\n// Prebuilding statement, no bind variables left\nStopwatch stopWatch2 = Stopwatch.createStarted();\nIterator<Entry<String, List<String>>> entries = dimensionMap.entrySet().iterator();\nEntry<String, List<String>> entry1 = entries.next();\nEntry<String, List<String>> entry2 = entries.next();\nString prebuilt = sql.replace(":domain", "\'" + domain + "\'")\n .replace(":key1", "\'" + entry1.getKey() + "\'")\n .replace(":values1",\n entry1.getValue().stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")))\n .replace(":key2", "\'" + entry2.getKey() + "\'")\n .replace(":values2",\n entry2.getValue().stream().map(s -> "\'" + s + "\'").collect(Collectors.joining(", ")));\nSet<Long> rs2 = extractIdSet(getNamedParameterJdbcTemplate().queryForRowSet(prebuilt, Collections.emptyMap()));\nlog.warn("Prebuilt took: {} ms", stopWatch2.elapsed(TimeUnit.MILLISECONDS));\n\n// Simple JDBCTemplate with 9 bind parameters\nStopwatch stopWatch5 = Stopwatch.createStarted();\nSet<Long> rs1 = extractIdSet(getJdbcTemplate().queryForRowSet(sqlWithBind,\n domain.toString(),\n entry1.getKey(),\n entry1.getValue().get(0),\n entry1.getValue().get(1),\n entry1.getValue().get(2),\n entry1.getValue().get(3),\n domain.toString(),\n entry2.getKey(),\n entry2.getValue().get(0)));\nlog.warn("JdbcTemplate took: {} ms", stopWatch5.elapsed(TimeUnit.MILLISECONDS));\n\n// Most beautiful: NamedJDBCTemplate\nStopwatch stopWatch3 = Stopwatch.createStarted();\nMap<String, Object> paramMap = createNamedParameterMap(domain, dimensionMap);\nSet<Long> rs3 = extractIdSet(getNamedParameterJdbcTemplate().queryForRowSet(sql, paramMap));\nlog.warn("NamedParameterJdbcTemplate took: {} ms", stopWatch3.elapsed(TimeUnit.MILLISECONDS));\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这是结果。确切的时间因运行而异,但始终保持在相同的数量级。
\n\nJdbcTemplate,性能会下降到爬行,大约需要 4 秒。NamedJdbcTemplate最简单、最灵活的 a 与情况 2 一样慢;至少这并不奇怪,因为在幕后NamedJdbcTemplate将使用命名参数替换我的查询,并将其替换为与情况 2 等效的内容。它\xe2\x80\x99s 没有获取连接,因为它们都从同一个连接池获取连接。它似乎不是queryForRowSet()单独的函数,因为 \xe2\x80\x99 实际上也在最快的情况下使用。同样,它看起来似乎与 Spring\xe2\x80\x99 的异常转换或参与正在进行的事务有任何关系,因为这也应该影响情况 1。
最后,问题是:JdbcTemplate与没有绑定参数的普通语句相比,为什么在这种情况下带有绑定参数的 Spring\xe2\x80\x99s 如此慢?
事实证明它既不是JdbcTemplate也不是NamedJdbcTemplate。PreparedStatement它也与vs无关Statement,即使后者是最快的。那只是因为普通语句不带有绑定参数。如果我的查询没有绑定参数,它\xe2\x80\x99s 与原始 JDBC 等的速度大致相同NamedJdbcTemplate。
我们的 Oracle 11 g只是为这个具有 9 个绑定参数的查询选择了一个错误的执行计划,并且无论实际参数是什么,都坚持它。我不知道为什么,也没有真正的 DBA。
\n\n在具有相同数据的 PostgreSQL 9.3 数据库上进行的测试表明,无论有没有绑定参数,它都同样快;带有开箱即用的 Ubuntu 安装。
\n| 归档时间: |
|
| 查看次数: |
2709 次 |
| 最近记录: |