Oracle CLOB性能

时间:2009-10-06 13:59:27

标签: performance oracle spring jdbc lob

我正在使用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检索?

4 个答案:

答案 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,您可能会考虑以下有趣的情况。

  • lob数据将竞争有限的SGA 如果是oracle,则缓存其他数据类型 决定缓存它。作为clob数据 一般大,所以它可能会推动其他 数据
  • lob数据获取可怜的磁盘读取 oracle决定不缓存它,并且 将数据流式传输到客户端。
  • 碎片可能是件事 你还没有遇到过。您将看到您的应用程序是否删除了lobs,并且oracle尝试重用lob。我不知道oracle是否支持在线对磁盘进行碎片整理(它们用于索引,但是我们之前尝试过它需要很长时间)。

你提到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进行更新,直到有人提出更好的想法。