9

我正在使用 JDBC(使用最新的驱动程序和 UCP 作为数据源)对 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

4 回答 4

7

结果集的总大小为一万 - 在整个检索的范围内测量初始成本

查询中是否有 Order By?如果必须对其进行排序,则 10K 行是相当多的。

此外,与检索整个 CLOB 相比,检索 PK 并不是一个公平的测试。Oracle 将可能包含许多行的表行存储在一个块中,但每个 CLOB(如果它们 > 4K)将被存储在一行之外,每个都存储在一系列块中。因此,扫描 PK 列表会很快。另外,PK上可能有索引,所以Oracle可以快速扫描索引块,甚至不访问表。

4 秒似乎有点高,但它需要 2MB 才能从磁盘读取并通过网络传输到您的 Java 程序。网络可能是个问题。如果您执行会话的 SQL 跟踪,它将准确地指出时间花费的位置(磁盘读取或网络)。

于 2009-10-07T13:32:20.700 回答
6

我过去使用oracle LOB类型数据存储大数据的经验一直不好。当它低于 4k 时很好,因为它像 varchar2 一样在本地存储它。一旦超过 4k,您就会开始看到性能下降。也许,自从我几年前上次尝试以来,情况可能有所改善,但以下是我过去发现的内容,供您参考:

由于客户端需要通过 oracle 服务器获取 LOB,您可以考虑以下有趣的情况。

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

您提到 100 lob 平均 20k 需要 4 秒,所以每个 lob 需要 40 毫秒。请记住,每个 lob 都需要通过单独的 Lob 定位器进行检索(默认情况下它不在结果集中)。我假设这是每个 lob 的额外往返行程(我不是 100% 确定这一点,因为那是不久前的事了) , 对?如果是这样,您的性能已经首先受到顺序 lob 提取的限制。您应该能够通过跟踪 sql 执行与 lob 内容获取所花费的时间来验证这一点。或者,您可以按照帖子中上一个答案的建议排除 lob 列来验证这一点,这应该告诉您它是否与 lob 相关。

祝你好运

于 2009-10-07T17:52:10.177 回答
6

我遇到了类似的问题,发现 JDBC Lobs 在访问 lob 时进行了网络调用。

从 Oracle 11.2g JDBC 驱动程序开始,您可以使用预取。这将访问速度提高了 10 倍...

statement1.setFetchSize(1000);
if (statement1 instanceof OracleStatement) {
    ((OracleStatement) statement1).setLobPrefetchSize(250000);
}
于 2014-04-17T15:52:05.573 回答
2

感谢所有有用的建议。尽管被标记为问题的答案,但我的答案是似乎没有好的解决方案。我尝试使用并行语句、不同的存储特性、预排序的温度。桌子和其他东西。该操作似乎不受任何通过痕迹或解释计划可见的特征的约束。当涉及到 CLOB 时,甚至查询并行性似乎也很粗略。

毫无疑问,在 11g 环境中处理大型 CLOB(尤其是压缩)会有更好的选择,但 atm. 我被困在10g。

我现在选择了额外的数据库往返,我将在其中将 CLOB 预处理为大小优化的二进制 RAW。在以前的部署中,这一直是一个非常快速的选择,并且可能值得维护离线计算缓存的麻烦。缓存将失效并使用持久进程和 AQ 进行更新,直到有人提出更好的主意。

于 2009-10-12T19:58:45.363 回答