我正在使用JDBC(使用最新的驱动程序和UCP作为DataSource)对Oracle 10g运行查询,以便检索CLOB(平均20k字符)。然而,性能似乎非常糟糕:批量检索100个LOB平均需要4个。根据我的观察,该操作既不是I / O也不是CPU,也不是网络限制。
我的测试设置如下:
PoolDataSource dataSource = PoolDataSourceFactory.getPoolDataSource();
dataSource.setConnectionFactoryClassName("...");
dataSource.setConnectionPoolName("...");
dataSource.setURL("...");
dataSource.setUser("...");
dataSource.setPassword("...");
dataSource.setConnectionProperty("defaultRowPrefetch", "1000");
dataSource.setConnectionProperty("defaultLobPrefetchSize", "500000");
final LobHandler handler = new OracleLobHandler();
JdbcTemplate j = new JdbcTemplate(dataSource);
j.query("SELECT bigClob FROM ...",
new RowCallbackHandler() {
public void processRow(final ResultSet rs) throws SQLException {
String result = handler.getClobAsString(rs, "bigClob");
}
});
}
我尝试了获取大小但无济于事。难道我做错了什么?有没有办法在使用JDBC时加快CLOB检索?
答案 0 :(得分:6)
结果集的总大小是一万个 - 在整个检索范围内测量的初始成本
查询中是否有订单?如果必须对10K行进行排序,则需要10K行。
此外,检索PK并不是检索整个CLOB的公平测试。 Oracle将表行存储在一个块中可能有很多,但每个CLOB(如果它们是> 4K)将被存储在行外,每个CLOB都在一系列块中。因此,扫描PK列表会很快。此外,PK上可能有一个索引,因此Oracle可以快速扫描索引块,甚至无法访问该表。
4秒确实看起来有点高,但是需要2MB才能从磁盘读取并通过网络传输到Java程序。网络可能是一个问题。如果您执行会话的SQL跟踪,它将指向您确切花费的时间(磁盘读取或网络)。
答案 1 :(得分:6)
我过去使用oracle LOB类型数据存储大数据的经验并不好。当它低于4k时它很好,因为它像varchar2一样在本地存储它。一旦超过4k,您就会开始看到性能下降。也许,自从我几年前上次尝试以来,情况可能有所改善,但以下是我过去发现的信息:
由于客户需要通过oracle服务器获取LOB,您可能会考虑以下有趣的情况。
你提到4s平均值为100k的平均值,所以它是每个lobs 40ms。请记住,需要通过单独的Lob定位器检索每个lob(默认情况下它不在结果集中)。这是每个吊球的额外往返,我假设(我不是100%肯定,因为它是在不久前)如果是这样的话,我认为每次往返至少5ms的连续顺序, 对?如果是这样,您的表现首先受到连续提升的限制。您应该能够通过跟踪sql执行与lob内容获取所花费的时间来验证这一点。或者您可以通过根据帖子中前一个答案的建议排除lob列来验证这一点,这应该告诉您它是否与lob相关。
祝你好运答案 2 :(得分:5)
我遇到了类似的问题,发现JDBC Lobs在访问lobs时进行网络调用。
从Oracle 11.2g JDBC驱动程序开始,您可以使用预取。 这加快了10次访问...
statement1.setFetchSize(1000);
if (statement1 instanceof OracleStatement) {
((OracleStatement) statement1).setLobPrefetchSize(250000);
}
答案 3 :(得分:2)
感谢所有有用的建议。尽管被标记为问题的答案我的答案是,似乎没有好的解决方案。我尝试使用并行语句,不同的存储特性,预分类temp。桌子和其他东西。该操作似乎不受通过痕迹或解释计划可见的任何特征的约束。当涉及CLOB时,甚至查询并行性似乎都是粗略的。
毫无疑问,在11g环境中处理大型CLOB(尤其是压缩)会有更好的选择,但是atm。我被困10g。
我现在选择了对数据库的额外往返,我将把CLOB预处理为大小优化的二进制RAW。在以前的部署中,这一直是一个非常快速的选择,并且可能值得维护离线计算缓存的麻烦。缓存将被无效并使用持久进程和AQ进行更新,直到有人提出更好的想法。