Большие объекты в СУРБД ORACLE. BLOB, CLOB

dbstalker, 02 июня

BLOB, CLOB – это внутренние большие объекты. Основные правила работы с этими объектами:

  • В основу работы с этими объектами положена транзакция, то есть любое изменение может быть зафиксировано или отменено.
  • Фактическое значение столбца LOB может храниться как часть строки таблицы, либо отдельно. Если длина столбца LOB больше 4000 байт, значение автоматически переносится в другое место.
  • Есть три состояния большого объекта: может быть пустым, может иметь значение null, может иметь какое-то конкретное значение. NULL – нет ни локатора ни значения у объекта. Пустой объект – имеется локатор, но он указывает на пустое место в базе данных.
  • Переменные и атрибуты объекта LOB могут играть роль промежуточного хранилища для локаторов LOB, указывающих на реальное значение в базе данных. То есть только поле таблицы может содержать значение объекта LOB. Переменная Lob не представляет никакого фактического значения. Переменная содержит только локатор, соответствующий полю lob в базе данных.
  • У каждого LOB–поля есть отдельный локатор и отдельное значение. То есть, если вы lob–полю присваиваете значение другого Lob-поля, то это поле получает новое значение и новый локатор.
  • Непротиворечивость чтения внутренних больших объектов обеспечивается с помощью собственных механизмов многовариантности.

Давайте посмотрим на некоторые примеры. Предположим, мы имеем табличку

CREATE TABLE DEMO (ID       INTEGER,  THEBLOB  BLOB)

Для инициализации больших объектов существуют следующие встроенные функции:

  function EMPTY_CLOB return clob;
  function EMPTY_BLOB return blob;
Эти функции создают пустой локатор.
insert into demo values (1,empty_blob());

Сделаем выборку

declare
the_id integer;
the_blob blob;
begin
SELECT   ID, THEBLOB into the_id, the_blob FROM DEMO where rownum=1;
end;

Так вот - в этом примере переменная the_blob получает локатор из столбца типа blob. Самого значения эта переменная не содержит, а содержит только указатель на местонахождение этого значения в базе данных.

А в следующем примере мы вставим новую строку в таблицу

declare
the_id integer;
the_blob blob;
begin
SELECT   ID, THEBLOB into the_id,the_blob FROM DEMO where rownum=1;
insert into demo values (2,the_blob);
end;

Теперь две строки имеют идентичное содержимое поля theblob, значения хранятся в разных местах, на которые указывают их отдельные локаторы.

Работа с внутренними большим объектами похожа на работу с другими типами данных, но подход ORACLE совершенно другой: доступ к ним реализуется через локаторы. Поэтому возникают некоторые проблемы в вопросе непротиворечивости чтения больших объектов.

Когда столбец внутреннего большого объекта меняет своё значение, предыдущее его значение не сохраняется в сегменте отката, как это происходит для других типов данных. Происходит все иначе: в пространстве, которое выделено для lob появляются дополнительные страницы, на которых и сохраняются предыдущие значения lob. Вывод: непротиворечивость чтения внутренних больших объектов достигается посредством их собственных механизмов многовариантности.

Обращаю ваше внимание, что все манипуляции с внутренними большими объектами производятся на основе транзакции. Когда транзакция, в которой прошла модификация Lob, зафиксирована, то дальнейшее использование соответствующего локатора становится некорректным. Локатор необходимо выбрать снова.

Давайте, углубимся в детали и посмотрим пример.

Когда локатор большого объекта выбрать в переменную lob, то это локатор становится согласованным по чтению. То есть, значение lob будет всегда таким, каким оно было на момент выбора локатора. Другими словами, когда локатор lob помещается в переменную, он получает СОБСТВЕННОЕ ПРЕДСТАВЛЕНИЕ значения lob.

В pl/sql возможны два способа обновления столбца внутреннего большого объекта: оператором update и пакетом dbms_lob. При использовании пакета dbms_lob, обновляемый локатор позволяет видеть результаты обновления. Чего нельзя сказать об операторе update. Чтобы увидеть новое значение, нужно по-новому выбрать обновленный столбец или использовать update с предложением returning .

А теперь пример с комментариями:

SQL> declare
  2  the_id integer;
  3  the_blob1 blob;
  4  the_blob2 blob;
  5  begin
  6  -- выбираем локатор согласованный по чтению
  7  SELECT   ID, THEBLOB into the_id,the_blob1 FROM DEMO where id=1;
  8  -- создадим еще один новый локатор согласованный по чтению
  9  the_blob2:=the_blob1;
 10  -- после следующего оператора записи с id=1 и id=2 будут иметь одинаковое значение столбца blob.
 11  update demo set theblob=the_blob2 where id=2;
 12  --после следующего оператора запись с id=1 буде иметь локатор чистый для столбца lob 
 13  update demo set theblob=empty_blob() where id=1;
 14  -- но мы еще можем видеть старое значение этого столбца. Поэтому создадим новую запись с эти значением
 15  insert into demo values ( 33,the_blob1) returning theblob into the_blob2;
 16  -- после этого оператора получем согласованный по чтению локатор в the_blob2
 17  
 18  delete FROM DEMO where id=1;
 19  --удаляем запись с  id=1, но все равно мы ещё можем получить значение столбца lob
 20  insert into demo values ( 44,the_blob1);
 21  commit;
 22  end;
 23  /

PL/SQL procedure successfully completed.

В этом примере наглядно показано, что при манипуляциях с большими внутренними объектами не следует читать или записывать их непосредственно, все манипуляции нужно реализовывать через локаторы.

Работать с внешними большими объектами можно с помощью пакета dbms_lob (см. нашу соответствующую статью).

12 комментариев

Прокоментировать

shindou
28 января 2009 г. в 15:44

А если после изменения theblob.empty_blob() сразу сделать коммит, то что будет с "телом" локатора (где хранится собственно значение ЛОБа), переданного the_blob1 (и the_blob2), и с самим локатором?

dbstalker
28 января 2009 г. в 17:02

если добавить commit после команды: update demo set theblob=empty_blob() where id=1; , то результат не изменится. в переменных the_blob1 и the_blob2 остается тоже значение, что и было. В записи с id=1 сначала будет пустой локатор, а потом эта запись удаляется.

shindou
29 января 2009 г. в 09:03

Спасибо большое!

То есть если изначально THEBLOB был не пустой, а содержал реальное значение - к примеру, 3 гигабайта, то при присваивании его значения переменной the_blob1 локатор дублируется и тело блоба тоже дублируется? Т. е. где-то создается еще один такой блоб размером 3 гигабайта? (А потом еще один - при присвоении значения the_blob2?) Где-нибудь во временном табличном пространстве? И потом (после завершения сеанса) оно так и остается +6 гигабайтов? Или переменные всё-таки хранятся в кэше каком-нибудь, который освобождается с завершением сессии?

shindou
29 января 2009 г. в 09:11

Ой, переменным передается же только локатор, но так как тело блоба не удаляется с обновлением локатора (the_blob1 и the_blob2 имеют доступ по старому локатору к телу блоба, локатор которого удален из поля таблицы), то можно предположить, что тело старого блоба, не имеющего локаторов в полях таблиц, остается нетронутым до конца сессии? Т. е. для нового блоба забирается новое место у операционной системы? Или это как-то по-другому устроено? Где находится "пространство, выделенное для лобов"? В SGA или временном табличном пространстве?

dbstalker
29 января 2009 г. в 09:25

Тело блоба физически находится в своем табличном пространстве. обратите большее внимание на специфический механизм многовариантности для таких типов объектов.

tpy
22 февраля 2009 г. в 06:37

Хочу уточнить.
Если я полю blob в операторе update укажу null. Данные будут удалены физически или нет? или для удаления данных полей Blob необходимо с начало очищать сам объект а потом обнулять локатор?

dbstalker
27 февраля 2009 г. в 10:41

Как толко вы выполнили такой update, то оракл считает, что нет ни локатора ни значения у объекта.Только не думайте, что табличное пространство сразу же уменьшится на размер BLOBа.

Nashev
3 февраля 2010 г. в 14:49

А когда же оно уменьшится?

dbstalker
4 февраля 2010 г. в 09:18

Табличное пространство без вмешательства администратора не уменьшается. НО в этом контексте вам интересно будет почитать на нашем блоге статьи про очистку блоков. Это интересно и почти в тему.

Nashev
3 февраля 2010 г. в 14:48

Фразу "У каждого LOB–столбца есть отдельный локатор и отдельное значение. То есть, если вы lob–столбцу присваиваете значение другого Lob-столбца, то этот столбец получает новое значение и новый локатор." стоит переписать корректнее: "У каждого LOB–поля есть отдельный локатор и отдельное значение. То есть, если вы lob–полю присваиваете значение другого Lob-поля, то это поле получает новое значение и новый локатор."

Ибо столбец - это множество полей из множества однотипных записей в таблице, у него не может быть одного значения. Одно значение - в одном поле одной записи.

Кроме того, стоит упомянуть в статье, к каким версиям Oracle относятся её утверждения.

dbstalker
4 февраля 2010 г. в 09:12

Спасибо. Исправляю.

rojd
6 января 2013 г. в 22:43

Нормально так)))

 

Новый комментарий

Я не спамер: введите суму 4+4



 

От авторов блога

О Блоге - прочитай перед началом.

Задать вопрос и получить ответ - уже решено 94 вопросов

Глоссарий - список терминов и сокращений


 
 

Бизнес форум

Последние темы:

Спутниковое тв
21 января, 3 ответа