Назад | Перейти на главную страницу

Oracle 11. Обновление BLOB-поля. Последовательное чтение файла db неуместно медленно?

Схема I и 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

Данные ТКПроф

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 строк. В то же время у меня есть другие таблицы в той же схеме с большими двоичными объектами (CLOB, чтобы быть более конкретными), которые содержат 600 + k строк, где аналогичные обновления работают правильно.

В Oracle LOB (включая BLOB) хранится как:

  • in-the-table LOB - если LOB меньше 3900 байт, он может храниться внутри строки таблицы; по умолчанию это включено, если вы не укажете ОТКЛЮЧИТЬ ХРАНИЛИЩЕ В СТРОКЕ
  • обычный LOB - хранится в отдельном сегменте, вне таблицы, вы даже можете поместить его в другое табличное пространство; для этих:
    • выделяется минимум байт CHUNK и полностью повторяется (даже если LOB имеет только 1 байт)
    • за столбцом LOB есть внутренний промежуточный индекс, который вызывает споры при обновлениях и может практически сериализовать их
    • доступ многоуровневый и поэтому относительно медленный
    • с опцией NOCACHE, официанты читают "прямой путь" - по умолчанию
    • с опцией CACHE, ожидающие будут "последовательным чтением файла db"
      • где CACHE_SIZE_THRESHOLD не учитывается, поэтому большой LOB может напрасно тратить ваш кеш

Следовательно, если ваши большие объекты больше 4 КБ, они будут относительно медленными, и это может быть просто ваш случай. Я бы рассмотрел размеры.

Я бы изучил USER_LOBS (или DBA_LOBS), чтобы увидеть, как «хорошие» и «медленные» столбцы LOB различаются по своим определениям.

Об этом говорится в заметке Metalink с идентификатором 66431.1, которая может вас заинтересовать, если у вас есть к ней доступ.

ОБНОВИТЬ: Очарованный, казалось бы, необъяснимым диким объемом "последовательного чтения файла db", я немного поискал и обнаружил, что странные вещи могут происходить с индексом lob после массовых DELETE. Просто предположение, но очень похоже на ваш случай. Если это так, я бы полностью перестроить столбец lob. (Перемещение столбца lob также может перестроить индекс lob - я не уверен).