E.20. lo

Модуль lo поддерживает управление большими объектами (БО или LO, Large Objects, иногда BLOB, Binary Large OBjects). Он реализует тип данных lo и триггер lo_manage.

E.20.1. Обоснование

Одна из проблема драйвера JDBC (она распространяется и на драйвер ODBC) в том, что спецификация типа предполагает, что ссылки на BLOB хранятся в таблице, и если запись меняется, связанный BLOB удаляется из базы.

Но с PostgreSQL этого не происходит. Большие объекты обрабатываются как самостоятельные объекты; запись в таблице может ссылаться на большой объект по OID, но при этом на один и тот же объект могут ссылаться несколько записей таблицы, так что система не удаляет большой объект, только потому что вы меняете или удаляете такую запись.

Это не проблема для приложений, ориентированных на PostgreSQL, но стандартный код, использующий JDBC или ODBC, не будет удалять эти объекты, в результате чего они окажутся потерянными — объектами, которые никак не задействованы, а просто занимают место на диске.

Модуль lo позволяет решить эту проблему, добавляя триггер к таблицам, которые содержат колонки, ссылающиеся на БО. Этот триггер по сути просто вызывает lo_unlink, когда вы удаляете или изменяете значение, ссылающееся на большой объект. Данный триггер предполагает, что на любой большой объект, на который ссылается контролируемая им колонка, указывает только одна ссылка!

Этот модуль также предоставляет тип данных lo, который просто является доменом на базе oid. Он может быть полезен для выделения колонок, содержащих ссылки на большие объекты, среди колонок, содержащих другие OID. Для использования триггера применять тип lo необязательно, но этот тип может быть полезен для отслеживания колонок в вашей базе, представляющих большие объекты, с которыми работает триггер. Кроме того, поступали сообщения, что драйвер ODBC не работает корректно, если для колонок BLOB используется не тип lo.

E.20.2. Как его использовать

Пример его использования:

CREATE TABLE image (title TEXT, raster lo);

CREATE TRIGGER t_raster BEFORE UPDATE OR DELETE ON image
    FOR EACH ROW EXECUTE PROCEDURE lo_manage(raster);

Для каждой колонки, которая будет содержать уникальные ссылки на большие объекты, создайте триггер BEFORE UPDATE OR DELETE и передайте имя колонки в качестве единственного аргумента триггера. Вы также можете сделать, чтобы триггер срабатывал только при изменениях в колонке, указав BEFORE UPDATE OF имя_колонки. Если вам нужно иметь в одной таблице несколько колонок lo, создайте отдельный триггер для каждой (при этом обязательно нужно дать всем триггерам в одной таблице разные имена).

E.20.3. Ограничения

  • При удалении таблицы, однако, всё равно будут потеряны относящиеся к ней объекты, так как триггер не будет выполняться. Этого можно избежать, выполнив перед DROP TABLE команду DELETE FROM таблица.

    То же касается и команды TRUNCATE.

    Если у вас уже есть, или вы подозреваете, что есть потерянные большие объекты, обратите внимание на модуль vacuumlo , который может помочь вычистить их. Имеет смысл периодически запускать vacuumlo в качестве меры, дополняющей действие триггера lo_manage.

  • Некоторые клиентские программы могут создавать собственные таблицы, но не создавать для них соответствующие триггеры. Кроме того, и пользователи могут не создавать такие триггеры (забывая о них, либо не зная, как это сделать).

E.20.4. Автор

Питер Маунт