我已经和 Oracle (11 Enterprise) 架构有一个表
CREATE TABLE USER.WSP_BUNDLE (
NODE_ID RAW(16) NOT NULL,
BUNDLE_DATA BLOB NOT NULL
);
CREATE UNIQUE INDEX USER.WSP_BUNDLE_IDX ON USER.WSP_BUNDLE(NODE_ID);
以及操作它的第三方库(Java 6,JDBC - 最新的 jdbc 驱动程序)。
Oracle 分析器(tkprof)显示大约 50% 的时间用于执行此类语句:
update WSP_BUNDLE set BUNDLE_DATA = :1 where NODE_ID = :2
TKProf 数据
Plan Hash: 4085453680
update WSP_BUNDLE set BUNDLE_DATA = :1 where NODE_ID = :2
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 264 0.00 0.00 0 0 0 0
Execute 400 30.59 382.88 141451 1623163 3233827 400
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 664 30.59 382.88 141451 1623163 3233827 400
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 87
Rows Row Source Operation
------- ---------------------------------------------------
0 UPDATE WSP_BUNDLE (cr=8753 pr=707 pw=706 time=0 us)
1 INDEX UNIQUE SCAN WSP_BUNDLE_IDX (cr=3 pr=0 pw=0 time=0 us cost=2 size=104 card=1)(object id 75730)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
db file sequential read 141251 5.53 328.04
direct path write 402 0.09 0.43
SQL*Net more data from client 142158 1.04 11.89
direct path read 200 0.03 0.07
Disk file operations I/O 1 0.00 0.00
SQL*Net message to client 400 0.00 0.00
SQL*Net message from client 400 0.29 0.50
log file switch (private strand flush incomplete)
5 0.05 0.23
asynch descriptor resize 139723 7.46 8.57
buffer busy waits 2 0.00 0.00
log file switch (checkpoint incomplete) 3 0.18 0.27
log file sync 2 0.00 0.00
有人能解释/提示我发生了什么吗?为什么更新这么慢?
表 WSP_BUNDLE 包含大约 200+k 行。同时,我在同一架构中还有其他包含 blob(更具体地说是 CLOB)的表,这些表包含 600+k 行,其中类似的更新可以正常工作。
答案1
在Oracle中,LOB(包括BLOB)存储为:
- 表中的 LOB - 如果 LOB 小于 3900 字节,则可以将其存储在表行内;默认情况下启用此功能,除非您指定 DISABLE STORAGE IN ROW
- 普通 LOB - 存储在表之外的单独段中,甚至可以将其放在另一个表空间中;例如:
- 分配最少的 CHUNK 字节并完全重做日志(即使 LOB 只有 1 个字节)
- LOB 列后面有一个内部中间索引,该索引在更新时会产生争议,并且实际上可能会序列化它们
- 访问是多级的,因此相对较慢
- 使用 NOCACHE 选项时,服务员是“直接路径读取” - 默认
- 使用 CACHE 选项时,等待者是“数据库文件顺序读取”
- 其中没有考虑 CACHE_SIZE_THRESHOLD,因此较大的 LOB 可能会浪费您的缓存
因此,如果您的 LOB 大于 4 kB,它们会变得相对较慢,这可能只是您的情况。我会检查大小。
我将检查 USER_LOBS(或 DBA_LOBS)以了解“好”和“慢”LOB 列在定义上有何不同。
Metalink 注释 ID 66431.1 对此进行了描述,如果您有权访问,您可能会感兴趣。
更新:我对看似无法解释的“数据库文件顺序读取”数量感到着迷,我做了一些搜索,发现大量删除后,lob 索引可能会发生奇怪的事情。只是猜测,但看起来和你的情况很相似。如果是这样的话,我会彻底重建 lob 列(移动 lob 列也可能会重建 lob 索引 - 我不确定)。