Oracle CLOB性能

yaw*_*awn 9 oracle performance 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");

            }

        });

}
Run Code Online (Sandbox Code Playgroud)

我尝试了获取大小但无济于事.难道我做错了什么?有没有办法在使用JDBC时加快CLOB检索?

Ste*_*ell 6

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

查询中是否有Order By?如果必须排序,10K行是相当多的.

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

4秒确实看起来有点高,但它需要2MB才能从磁盘读取并通过网络传输到Java程序.网络可能是一个问题.如果您执行会话的SQL跟踪,它将指向您确切花费的时间(磁盘读取或网络).


Osc*_*han 6

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

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

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

你提到4s平均每100磅平均值,所以它是每个lobs 40ms.请记住,需要通过单独的Lob定位器检索每个lob(默认情况下它不在结果集中).这是每个吊球的额外往返,我假设(我不是100%肯定,因为它是在不久前)如果是这样的话,我认为每次往返至少5ms的连续顺序, 对?如果是这样,您的表现首先受到连续提升的限制.您应该能够通过跟踪sql执行与lob内容提取所花费的时间来验证这一点.或者您可以通过排除帖子中前一个答案建议的lob列来验证这一点,这应该告诉您它是否与lob相关.

祝好运


小智 6

我有一个类似的问题,发现在lob中访问时JDBC Lob进行了网络调用。

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

statement1.setFetchSize(1000);
if (statement1 instanceof OracleStatement) {
    ((OracleStatement) statement1).setLobPrefetchSize(250000);
}
Run Code Online (Sandbox Code Playgroud)


yaw*_*awn 2

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

毫无疑问,除了 atm 之外,在 11g 环境中还有更好的选择来处理大型 CLOB(尤其是压缩)。我被10g困住了。

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