performance - Oracle 10g 小 Blob 或 Clob 没有被内联存储?

标签 performance oracle blob inline clob

根据我读过的文档,CLOB 或 BLOB 的默认存储是内联的,这意味着如果它的大小小于大约 4k,那么它将被保存在表中。

但是,当我在 Oracle (10.2.0.1.0) 中的一个虚拟表上对此进行测试时,Oracle Monitor(由 Allround Automations 提供)的性能和响应表明它与表无关。

这是我的测试场景...

create table clobtest ( x int primary key, y clob, z varchar(100) )  
;
insert into clobtest 
   select object_id, object_name, object_name  
   from all_objects where rownum < 10001  
;
select COLUMN_NAME, IN_ROW 
from user_lobs 
where table_name = 'CLOBTEST'  
;

这显示:Y YES(建议 Oracle 将 clob 存储在行中)
select x, y from CLOBTEST where ROWNUM < 1001 -- 8.49 seconds  
select x, z from CLOBTEST where ROWNUM < 1001 -- 0.298 seconds  

所以在这种情况下,CLOB 值的最大长度为 30 个字符,因此应该始终是内联的。如果我运行 Oracle Monitor,它会为返回的每一行显示一个 LOB.Length,后跟一个 LOB.Read(),这再次表明 clob 值与表保持一致。

我也尝试过像这样创建表格
create table clobtest 
    ( x int primary key, y clob, z varchar(100) ) 
    LOB (y) STORE AS     (ENABLE STORAGE IN ROW)  

但得到完全相同的结果。

有人对我如何强制(说服、鼓励)Oracle 将 clob 值在线存储在表中提出任何建议吗? (我希望达到与读取 varchar2 列 z 类似的响应时间)

更新:如果我运行这个 SQL
select COLUMN_NAME, IN_ROW, l.SEGMENT_NAME, SEGMENT_TYPE, BYTES, BLOCKS, EXTENTS 
from user_lobs l 
      JOIN USER_SEGMENTS s
       on (l.Segment_Name = s. segment_name )
where table_name = 'CLOBTEST'  

然后我得到以下结果......
Y   YES SYS_LOB0000398621C00002$$   LOBSEGMENT  65536   8   1  

最佳答案

Oracle LOB 的行为如下。

LOB 在以下情况下内联存储:

(
  The size is lower or equal than 3964
  AND
  ENABLE STORAGE IN ROW has been defined in the LOB storage clause
) OR (
  The value is NULL
)

LOB 在以下情况下存储在行外:
(
  The value is not NULL
) AND (
  Its size is higher than 3964
  OR
  DISABLE STORAGE IN ROW has been defined in the LOB storage clause
)

现在,这不是可能影响性能的唯一问题。

如果 LOB 最终没有内联存储,Oracle 的默认行为是避免缓存它们(只有内联 LOB 与行的其他字段一起缓存在缓冲区缓存中)。为了告诉 Oracle 也缓存非内联 LOB,应在定义 LOB 时使用 CACHE 选项。

默认行为是 ENABLE STORAGE IN ROW 和 NOCACHE,这意味着小 LOB 将被内联,大 LOB 不会(并且不会被缓存)。

最后,在通信协议(protocol)层面也存在性能问题。典型的 Oracle 客户端将为每个 LOB 执行 2 次额外的往返来获取它们:
- 一种检索 LOB 的大小并相应地分配内存
- 一个获取数据本身(假设 LOB 很小)

即使使用数组接口(interface)来检索结果,也会执行这些额外的往返。如果您检索 1000 行并且您的数组大小足够大,您将支付 1 次往返来检索行,以及 2000 次往返来检索 LOB 的内容。

请注意 不是 取决于 LOB 是否内联存储的事实。它们是完全不同的问题。

为了在协议(protocol)级别进行优化,Oracle 提供了一个新的 OCI 动词,用于在一次往返中获取多个 LOB (OCILobArrayRead)。我不知道 JDBC 是否存在类似的东西。

另一种选择是在客户端绑定(bind) LOB,就好像它是一个大的 RAW/VARCHAR2。这仅在可以定义 LOB 的最大大小时才有效(因为必须在绑定(bind)时提供最大大小)。这个技巧避免了额外的往返:LOB 就像 RAW 或 VARCHAR2 一样被处理。我们在 LOB 密集型应用程序中经常使用它。

一旦优化了往返次数,就可以在网络配置中调整数据包大小 (SDU) 的大小以更好地适应情况(即有限数量的大型往返)。它倾向于减少“SQL*Net more data to client”和“SQL*Net more data from client”等待事件。

关于performance - Oracle 10g 小 Blob 或 Clob 没有被内联存储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7361729/

相关文章:

API >= 14 上的 Android 应用程序 onLowMemory()

performance - Option.isEmpty 的更快实现?

database - 将集群添加到oracle中的现有表

node.js - 如何发送外部文件,只使用 url(https ://. ....)

c++ - Sqlite C++ 图像到 Blob 不会存储任何内容

javascript - 降低 Javascript 中 DOM 搜索频率

mysql - MySQL 和 Oracle DB 之间的差异

SQL查询问题

java - 从 java 调用 SQLLoader,加载名称包含 @ 符号的文件时出现问题

azure - 从存储在 blob 中的 ISO 创建 Azure VM