2009-10-06 116 views
8

我正在使用JDBC(使用最新的驱动程序和UCP作为DataSource)对Oracle 10g执行查询以检索CLOB(平均20k字符)。但是性能似乎相当糟糕:100个LOB的批量检索平均需要4秒。从我的观察结果来看,该操作既不是I/O也不是CPU,也不是网络界限。Oracle CLOB性能

我的测试设置是这样的:

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

你是怎么确定它没有网络绑定的?您正在讨论设置新的JDBC连接(价格昂贵),2Mb的数据从磁盘读取,通过网络发送以及查询开销(未指定)。根据您的网络布局和数据库设置,我不知道4s是不是很糟糕。 – Gandalf 2009-10-06 17:38:13

+0

澄清:我测量的*单位*为100,因此连接的初始处罚不计算在内。总的网络吞吐量保持在2Mbit/s以下,所以我认为它不受网络限制。 – yawn 2009-10-06 19:12:03

+0

实际查询需要多长时间? – Gandalf 2009-10-06 20:35:52

回答

2

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

毫无疑问,在11g环境中处理大型CLOB(特别是压缩)会有更好的选择,但atm。我坚持10g。

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

+0

看起来像一个很好的解决方法,就好像您检索100行一样,您将支付额外往返票,但可节省100次往返票,完全可以节省100-1 = 99次往返票。但你是如何实现它的? – user451795 2010-11-19 08:14:07

+0

通过仅提取CLOB +某些键以稍后识别它们并将它们写入本地键值存储区。我使用了[Oracle Berkeley DB](http://www.oracle.com/technetwork/database/berkeleydb/overview/index.html),但是您可以轻松使用SQLite或其他任何我想要的东西。 – yawn 2010-11-19 09:28:02

6

结果集的总大小是在一万 - 在整个检索的标准来衡量初始成本

有一个ORDER BY查询?如果要排序的话,10K行相当多。

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

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

5

我以前使用oracle LOB类型数据存储大数据的经验并不好。当它在4k以下时很好,因为它像varchar2一样在本地存储它。一旦超过4k,你开始看到性能下降。也许,自从我上一次尝试它之后,事情可能会有所改进,但以下是我在过去为您提供的信息:

由于客户端需要通过Oracle服务器获取LOB,因此可以考虑以下有趣的情况。如果甲骨文 决定缓存它

  • LOB数据将争夺有限的SGA 缓存与其他数据类型。为CLOB数据 一般大,所以它可能会推动其他 数据
  • LOB数据得到,如果 甲骨文决定不再缓存它,并 数据流的客户端磁盘读取差。
  • 碎片可能是 ,您还没有遇到过。你会看到你的应用程序是否删除lob,并且oracle会尝试重新使用lob。我不知道oracle是否支持在线碎片整理磁盘碎片(他们有索引,但是我们之前尝试它需要很长时间)。

你提到4个100g的平均20k,所以它是40ms每个鱼子。请记住,每个高球需要通过单独的Lob定位器进行检索(默认情况下,它不在结果集中)。对于每个吊球来说,这是一个额外的往返行程,我假设(我不是100%确定的,因为它是前一阵子)如果是这样的话,我假设每个往返顺序至少有5ms额外时间, 对?如果是这样,你的表现已经首先受到顺序吊索取消的限制。您应该能够通过跟踪在执行sql与lob lob内容获取中花费的时间来验证这一点。或者您可以通过排除帖子中前一个答案建议的lob列来验证这一点,该列会告诉您它是否与lob有关。

好运

3

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

从Oracle 11.2g JDBC驱动程序开始,您可以使用预取。 加速访问10次...

statement1.setFetchSize(1000); 
if (statement1 instanceof OracleStatement) { 
    ((OracleStatement) statement1).setLobPrefetchSize(250000); 
}