Lobsegment oracle что это
Можно переместить LOB сегмент в табличное пространство, которое располагаются на более медленных устройствах хранения, но больших по объему и относительно дешевых.
Чтобы освободить место в табличном пространстве за счет LOB сегмента, можно использовать три способа:
A) Освободить неиспользуемое место выше High Water Mark (HWM).
B) Сделать SHRINK. В сегменте освободиться неиспользуемое место и место под удаленными данными.
C) Физически переместить LOB сегмент в другое табличное пространство.
ВНИМАНИЕ: Во время выполнения запросов из способов B) и C) LOB сегмент блокируется. Если LOB сегмент большой, то это может занять значительное время. Поэтому эти операции рекомендуется проводить во вне рабочее время.
Сначала определяем, с какими сегментами мы будем работать
0) Определяем размер LOB сегментов, чтобы понять какие из них самые большие
1) Сегмент может занимать больше места, чем в нем содержится данных. Этим запросом можно определить, сколько места занимают реальные данные конкретного сегмента.
Если место занимаемое данными намного меньше самого сегмента, значит есть свободное место в самом сегменте и его можно попробовать освободить способами A) и B)
Если данные занимают весь сегмент — значит чтобы освободить место в табличном пространстве его нужно переносить в другое табличное пространство.
Вместо переменных подставить:
— поле table_name из запроса 0
— поле segment_name из запроса 0
A.1) Процедура показывает, сколько места можно освободить командой ALTER TABLE … DEALLOCATE UNUSED.
Если такого места много и вы хотите освободить его — выполните A.2.
Если такого места мало тогда место используйте способы B) или С).
A.2) Если такого места много его можно освободить командой
— поле table_name из запроса 0
— поле COLUMN_NAME из запроса 0
alter table ELA_DOCUMENT modify lob (ELADO_BYTES) (deallocate unused);
B.1) Процедура показывает, сколько места можно освободить командой ALTER TABLE … DEALLOCATE UNUSED.
Если такого места много и вы хотите освободить его — выполните A.2.
Если такого места мало тогда место используте способы B) или С).
— поле table_name из запроса 0
— поле COLUMN_NAME из запроса 0
alter table ELA_DOCUMENT modify lob(ELADO_BYTES) (shrink space);
alter table ELA_DOCUMENT modify lob(ELADO_BYTES) (shrink space cascade);
Опция cascade — применяет SHRINK не только к LOB сегменту но и к связанным с ним LOB индексам
C.1) Запрос которым LOB сегмент переноситься в другое табличное пространство
Вместо переменных подставить:
— поле table_name из запроса 0
— поле COLUMN_NAME из запроса 0
— имя табличного пространства в которое вы хотите перенести LOB сегмент
ALTER TABLE ELA_DOCUMENT MOVE LOB(ELADO_BYTES) STORE AS (TABLESPACE DATA2);
Существует несколько типов LOB объектов: BLOB (двоичный большой объект), CLOB (символьный большой объект), NCLOB (национальный символьный большой объект) и BFILE (внешний двоичный файл). LOB объекты делятся на внутренние и внешние.
- постоянные LOB создаются как столбцы таблицы БД командой CREATE таблицы, при этом данные LOB могут храниться как в самой таблице, так и вне таблицы;
- временные Temporary LOB создается для использования только в пределах конкретного приложения. Для создания временного LOB используется процедура DBMS_LOB.CREATETEMPORARY.
Внешние большие объекты External LOB – вид данных, который хранится в файлах операционной системы, вне базы данных, а в базе данных на них хранятся ссылки (локаторы). Внешние LOB используют тип данных – BFILE.
- локатор-указатель, который специфицирует местонахождение контента, т.е. собственно данных LOB объекта;
- контент – набор двоичных или символьных байтов, составляющих LOB.
Инструментом работы с LOB выступает пакет DBMS_LOB. Он предоставляет методы манипулирования внутренними и внешними LOBами.
В данной статье рассматриваются только постоянные внутренние LOB объекты.
Модель хранения данных Oracle
Разделение логической и физической структур является необходимой частю парадигмы реляционных баз данных. Парадигма гласит что программисты должны работать только с логическими структурами и позволять базе данных управлять их соответствием физическим структурам. Это значит что физическая структура может быть преобразована, или к примеру целиком база данных переведена на новое аппаратное обеспечение и операционную системы, а на работу приложений это не должно оказывать никакого влияния.
На рисунке 5-1 отображена модель Oracle как диаграмма сущность-связь, с логическими структурами слева и физическими структурами справа.
На этом рисунке одна линия связи отображена пунктирной линией: связь многие-ко-многим между сегментами и файлами данных. Эта линия выделена пунктиром, так как её не должно быть, отношение многие-ко-многим не допускаются хорошими DBA. Преобразование этой взаимосвязи к нормализованному виду и есть задача организации модели хранения.
Введение сущности табличное пространство (tablespace) разрешает взаимосвязь многие-ко-многим между сегментами и файлами данных. Одно табличное пространство может содержать несколько сегментов и состоять из нескольких файлов данных. Т.е. один сегмент может быть разделён между многими файлами данных, и один файл данных может содержать данные разных сегментов. Это решает много проблем организации хранения данных. В некоторых более старых РСУБД использовалась связь один-к-одному между сегментом и файлом данных: каждая таблица или индекс хранилась как отдельный файл. Это вызывало две большие проблемы для больших систем.
Во первых, в приложении могут использоваться тысячи таблиц и ещё больше индексов; управление тысячами файлов нелёгкая задача для системных администраторов. Во вторых, максимальный размер таблицы ограничен максимальным размером файла. Даже в современных ОС в которых нет ограничений по размеру файла – могут возникнуть проблемы из-за ограничений на аппаратном уровне. Использование табличных пространств решает обе эти проблемы. Табличным пространствам в базе данных присваиваются уникальные имена. Сущность сегмент (segment) представляет собой любой объект базы данных который хранит информаци и таким образом нуждается в пространстве внутри табличного пространства. Типичным примеро сегмента является таблица, но существуют и другие типы сегментов, индексы и сегменты undo. Сегмент может хранится тоьлко в одном табличном пространстве, но само табличное пространство может быть разбитым между многими файлами, которые составляют это табличное пространство. Таким образом размер таблицы больше не ограничивается максимальным размером одного файла. Так как много сегментов могут использовать одно табличное пространство, то становится возможным иметь куда больше сегментов, чем файлов данных. Сегменты это объекты которые принадежат схеме и идентифицируются они именем сегмента с именем схемы-владельца. Программируемые объекты схемы (такие как PL/SQL процедуры, представления или последовательности) не являются сегментами: они не хранят данные и хранятся в словаре данных.
Блоки Oracle это базовая единица операций чтения и записи для базы данных. Файлы данных форматированны на последовательно пронумерованные блоки Oracle. Размер блока определяется для табличного пространства (в общем он един для всех табличных пространств в пределах базы данных), по умолчанию (версия 11g) используется значения 8Кб. Строка может занимать всего несколько сотен байт, поэтому внутри одного блока может хранится несколько строк, но когда сессия хочет получить строку, будет вычитываться целый блок с диска и помещаться в кэш буфера. Также если изменилось значение только одного столбца для одной строки в буфере кэша – DBWn перезапишет на диск весь блок в файл данных откуда он был считан затерев старый. Размер блока Oracle может быть от 2ух до 16 Кб на операционных системах Linux или Windows и до 32 Кб в некоторых других системах. Размер блока контролируется параметром DB_BLOCK_SIZE. После создания базы данных нельзя изменить значение этого параметра, так как он используется для форматирования файлов данных табличного пространства SYSTEM. Если позже оказалось что необходимо изменить значение этого параметра, единственным решением будет создать новую базу и скопировать в неё все из уже созданной. Блок внутри файла можно идентифицировать по его уникальному номеру.
Управление дисковым пространством по одному блоку за раз было бы очень трудоёмкой задачей, поэтому блоки группируются в экстенты (extent). Экстентом называется набор последовательных блоков внутри одного файла данных. Каждый сегмент состоит из одного или более экстентов, последовательно пронумерованных. Эти экстенты могут находиться в любом или во всех из доступных для табличного пространства файлов данных. Экстент можно идентифицировать как внутри сегмента (экстенты последовательно пронумерованы в пределах сегмента начиная с нуля) так и внутри файла данных (каждый сегмент находится только в одном файле данных, начиная с определённого блока Oracle).
Файл данных физически состоит из блоков операционной системы. Как структурированы блоки операционной системы внутри файла данных целиком зависит от файловой системы используемой операционной системой. Некоторые файловые системы имеют общеизвестные ограничения и поэтому не используются в современных системах (например старая файловая система MS-DOS FAT поддерживает файлы размером до 4 Гб и всего 512 файлов в одной директории). Большинство баз данных устанавливается на файловые системы без практических огранчений, такие как NTFS в Windows или ext3 в Linux. Альтернативой файловой системе является хранение файлов данных на raw device-ах или Automatic Storage Management (ASM).
Блок операционной системы это базовый элемент операция записи чтения для файловой системы. Если процесс хочет прочитать один байт с диска подсистема ввода-вывода всё равно считает системный блок целиком. Размер блока операционной системы можно настраивать на некоторых ОС (например когда форматируется диск под файловую систему NTFS можно указать размер блока от 512 байт до 64 Кб), но обычно системные администраторы оставляют значения по умолчанию (512 Б для NTFS и 1Кб для ext3). Вот почему обычно отношение между блоками Oracle и блоками ОС обычно один-ко-многим, как показано на рисунке 5-1. Ничего не мешает сделать размер блока ОС равным размеру блока Oracle если ваша операционная система позволяет сделать это. Единственная конфигурация которой стоит избегать это когда размер системного блока больше чем размер блока Oracle.
Практический пример
Представляется, что лучше всего представить концепцию SecureFiles с помощью простого примера. Предположим, вы разрабатываете систему документооборота, в которой хотите поместить в таблицу копии договоров. Обычно отсканированные документы представляют собой не текстовые, а PDF-файлы, а некоторые - документы MS Word или даже отсканированные рисунки. Это отличный пример для использования BLOB-объектов, так как такой столбец таблицы должен содержать двоичные данные.
Традиционное до Oracle Database 11g определение таблицы было бы следующим:
Реальные файлы хранятся в двоичном формате в столбце ORIG_FILE. Другие параметры показывают, что LOB-объект не должен кешироваться и журналироваться в операциях, что он хранится в строке таблицы, имеет размер порции (chunk) 4 КБ, и lob-сегмент находится в табличном пространстве USERS. Поскольку это явно не определено, LOB-объекты хранятся в Oracle Database 11g в общепринятом формате (BasicFiles).
Если надо хранить LOB-объект в виде SecureFile, то все, что необходимо сделать, это при создании таблицы дописать фразу store as securefile, как показано ниже:
Для того чтобы создать LOB-объект в виде SecureFile, необходимо выполнить два условия, причем оба выполняются по умолчанию (так что можно быть спокойным).
Параметр инициализации db_securefile должен быть установлен в permitted (значение по умолчанию). Я объясню, что это за параметр позднее.
Созданное табличное пространство, где размещаются сохраняемые (securefile) файлы, должно быть Automatic Segment Space Management (ASSM). ASSM - режим по умолчанию при создании табличного пространства в Oracle Database 11g, поэтому он уже установлен для табличного пространства. Если это всё же не так, тогда необходимо размещать SecureFiles в другом табличном ASSM-пространстве.
После того, как таблица создана, можно загружать данные тем же способом, как и обычные (до 11g) LOB-объекты (BasicFile). Не надо изменять приложения и не надо запоминать какой-то специальный синтаксис.
Вот пример небольшой программы, которая загружает данные в таблицу:
Эта программа 100 раз загружает файл contract.pdf в 100 строк таблицы. Заранее надо иметь определенный объект типа directory, названный SECFILE, определяющий директорию операционной системы, где расположен файл contract.pdf. Ниже приводится пример, в котором файл contract.pdf расположен в директории /opt/oracle.
Один раз сохранив LOB-объект как SecureFile, вы получаете множество возможностей для выполнения оптимальных действий. Приведем несколько примеров этих весьма полезных возможностей.
Сегменты LOB объектов Oracle
При создании и заполнении данными таких объектов Oracle как LOB объект, таблица, индекс и др. для каждого объекта создается структура, называемая сегментом. При этом имеется особенность при создании сегментов: для каждой не секционированной таблицы создается только один сегмент, для одного не секционированного индекса создается только один сегмент, для каждой секции секционированной таблицы и для каждой секции индекса создается свой сегмент. Однако для каждого LOB столбца таблицы создается не один, а два сегмента. Один сегмент - это LOB-сегмент для хранения данных и второй – это LOB индексный сегмент. LOB индексный сегмент создается автоматически при создании LOB-сегмента и служит для навигации по LOB-сегменту.
Таким образом, если в таблице было указано N столбцов типа LOB, то получим 2*N LOB-сегментов.
LOB сегменты можно увидеть из представления DBA_LOBS запросом:
Рассмотрим порядок работы с таблицами, имеющими LOB столбцы, на примере таблицы AIS.SERVICEMSGXML, функционирующей в нашей системе. В таблице имеются два LOB столбца: XMLOUT и XMLIN - оба типа CLOB.
Команда создания таблицы имеет вид:
LOB сегменты этой таблицы можно увидеть из представления DBA_LOBS указанным выше запросом:
В результате получаем:
Мы видим, что в именах сегментов имеются символы SYS_LOB для LOB-сегментов и SYS_IL для индексных сегментов.
Используя представление Oracle DBA_SEGMENTS (при наличии данных в LOB), можно получить размер в байтах, занимаемых LOB-сегментами и LOB-индексными сегментами. Например, для LOB столбца XMLOUT число байтов, занимаемых сегментом, определяется запросом, указанным ниже. При этом в запросе в поле segment_name подставляется имя сегмента, полученного из представления DBA_LOBS.
В результате работы запроса получаем:
Для работы с LOB удобным является запрос, в котором используются оба указанных выше представления: DBA_SEGMENTS и DBA_LOBS. Данный запрос покажет (при наличии данных в LOB) не только LOB сегменты всей таблицы и ее индексов, но и размеры в байтах, которые они занимают.
Иногда важно посмотреть объем, занимаемый самой таблицей без LOB объектов. Это можно увидеть (при наличии данных в таблице) запросом:
Как видно, сама таблица составляет порядка 8 MB, в то время как один из LOB занимает 6900 MB. В силу чего таблица была размещена в табличном пространство ADATA среднего размера, в то время как LOB большого объема был размещен в другом существенно большем табличном пространстве LOBTBS. О табличных пространствах LOB изложено ниже.
Внутренние двоичные объекты (BLOB) базы данных и файлы операционной системы
Что находится в базе данных Oracle? В большинстве случаев это - данные, хранимые в виде, пригодном для простого преобразования в некий определенный шаблон заданного типа данных: имена пользователей, остатки на счетах, коды состояний и т.п. Но со столь же большой долей вероятности может понадобиться хранение данных в неструктурированном или полуструктурированном виде. Например, изображения, текстовые документы, таблицы, XML-файлы и так далее. Как хранятся эти типы данных?
Обычно используется два подхода: такие данные хранятся в базе данных как LOB-объектов (BLOB для двоичных и CLOB для символьных данных) или в виде файлов операционной системы, а в базе данных хранятся на них ссылки.
Каждый подход имеет достоинства и недостатки. Файлы операционной системы могут кешироваться и журналироваться средствами операционной системы, что ускоряет их восстановление после сбоев. К тому же они обычно занимают меньше места, чем данные в базе данных, поскольку могут быть сжаты.
Существуют также средства, которые позволяют распознавать такие структуры (patterns) в файлах и удалять повторяющиеся элементы для более эффективного хранения. Но они не являются частью базы данных и не имеют ее свойств. Резервное копирование таких файлов не выполняется, не доступны тонкости политики безопасности, эти файлы не являются частью транзакций, то есть целостность данных - первичная концепция базы данных Oracle - на них не распространяется.
Как же воспользоваться преимуществами каждого подхода? В Oracle Database 11g имеется ответ – SecureFiles (сохраняемые файлы), совершенно новая инфраструктура в базе данных, которая объединяет лучшие особенности LOB-объектов базы данных и файлов операционной системы. Давайте рассмотрим, как они работают. (Кстати, традиционные LOB-объекты до сих пор доступны в виде так называемых BasicFiles).
Задание табличного пространства для LOB столбцов таблицы
По умолчанию LOB-сегмент со своим LOB индексным сегментом создается в том же табличном пространстве, что и таблица, в которой находятся LOB столбец. При этом весьма важный момент: LOB-сегмент и LOB-индекс всегда находятся в одном и том же табличном пространстве.
Однако порой целесообразно помещать LOB сегмент в табличное пространство, отличное от пространства таблицы. При этом сами LOB столбцы так же могут размещаться в различных табличных пространствах.
Для размещения LOB в другое табличное пространство, отличное от пространства таблицы, используется структура STORE (начиная с Oracle 11g можно использовать структуру STORE AS SECUREFILE) в команде CREATE таблицы. При этом фразу STORE можно указать только при создании таблицы, т.е. STORE нельзя вставить в процессе модификации таблицы.
Замечание. При создании таблицы по команде Create table с LOB столбцами в ней автоматически для каждого LOB столбца таблицы создается структура STORE. Например, для столбца XMLOUT типа LOB по умолчанию создалась бы структура STORE вида:
В ней по умолчанию табличным пространство LOB-а становиться табличное пространство таблицы ADATA и автоматически создаются несколько параметров.
Если есть необходимость управлять табличным пространством или параметрами STORE, надо явно описать конструкцию STORE при создании таблицы (что и было сделано при создании таблицы AIS.SERVICEMSGXML по каждому LOB столбцу). При этом, если используется конструкция STORE AS SECUREFILE, то ее необходимо явно прописывать в команде Create table.
- Фраза TABLESPACE, указывающая в каком табличном пространстве создается LOB сегмент (соответственно и его LOB-индексный сегмент).
- Фраза ENABLE. По умолчанию создается ENABLE STORAGE IN ROW - это означает, что LOB размером до 4000 байт будут храниться в самой таблице (сегменте таблицы), а LOB-ы, который больше 4000 байт, будут храниться в LOB сегменте вне таблицы. При DISABLE STORAGE IN ROW -все значения LOB попадают в LOB сегменты, т.е. вне таблицы.
При этом предпочтительнее ставить ENABLE STORAGE IN ROW, если в основной массе случаев размер LOB меньше 4000 байт, т.е. LOB-ы умещаются в таблице. В отсутствии кэширования LOB, каждое обращение к LOB (чтение или запись) задействует физическую операцию ввода-вывода. Таким образом, хранение LOB-ов в таблице позволяет существенно сократить операции физического ввода-вывода на извлечение, запись и модификацию LOB-ов. ENABLE позволяет так же уменьшить число логических операциях ввода-вывода, обусловленных обращением к LOB-индексу.
Замечание. Для принятия решения, какой метод принять ENABLE STORAGE IN ROW или DISABLE может использоваться функция GETLENGTH пакета DBMS_LOB.
Данная функция определяет размер LOB в байтах для BLOB и BFILE или длину LOB в символах для CLOB. При этом перевод числа символов в число байтов зависит от кодировки, так для ASCII и ряда других кодировок один символ = 1 байт. Таким образом, функция GETLENGTH практически в этом случае даст тоже размер в байтах.
При этом ценность функции в том, что она позволяет показать не общую сумму байт, занимаемую LOB, а число байт, занимаемую LOB по строкам таблицы. В силу чего можно оценит, какой процент строк занимает менее 4000 байт и принять решение по поводу фразы ENABLE.
Например, для столбца XMLIN типа CLOB число символов, занимаемое соответствующими строками таблицы SERVICEMSGXML, определяется запросом
Вычислить процент строк, в которых LOB типа BLOB составляют менее 4000 байт можно по запросу
- Фраза COMPRESS. Задает режим сжатия: HIGH –высокое сжатие , MEDIUM-среднее (по умолчанию) и LOW-низкое. Сжатие происходит внутри LOB, каждый LOB сжимается независимо от других. При этом сжатие LOB не зависит от сжатия таблиц. Так если задали режим сжатия таблицы, то это не приведет автоматически к сжатию ее LOB и наоборот. При выборе режима сжатия надо учитывать, что оно требует работы процессора, так в режиме LOW хотя и получаем минимальное сжатие, однако потребуется намного меньше потребление процессорных ресурсов, кроме того обеспечивается более высокая скорость процесса.
Для проверки эффективности сжатия можно использовать указанный выше пакет DBMS_LOB.GETLENGTH. Для этого оценивается размер LOB до сжатия и после сжатия (за какой-то период времени t). Например, для LOB XMLIN может использоваться запрос
Перед этим можно убрать режим сжатия LOB через NOCOMPRESS по команде
Выполнить указанный выше запрос через время t, за которое будут проведены вставки данных в таблицу, а затем ввести режим сжатия в таблицы
Посчитать объем (в байтах) данных, введенных в таблицу за тоже t время, после чего сравнить результаты. - Фраза DEDUPLICATE запускает режим дедубликации. В этом режиме повторяющиеся значения в LOB заменяются указателями, что экономит табличное пространство.
Вывод. При создании STORE cледует оценить, что эффективнее: хранить LOB в таблице или вынести их из таблицы (режим ENABLE или DISABLE), обосновать целесообразность кэширования LOB и определить более эффективный размер CHUNK.
Сегменты, экстенты, блоки и строки
Данные хранятся в сегментах. Представление словаря данных DBA_SEGMENTS хранит инфомрацию обо всех сегментах в базе данных. Запрос ниже отображает все типы сегментов в простой БД
Рассмотрим эти сегменты:
- Таблица (Table) — это структура которая хранит строки данных. Несмотря на то что наиболее часто встречающийся сегмент это таблица, никогда нельзя путать таблицу и сегмент, и что существуют гораздо более сложеные в организации таблицы которые используют другой тип сегмента
- Индекс (Index) это сортированный список ключей-значений, каждая из которых зранит указатель ROWID на физическое расположение строки. ROWID определяет в каком блоке Orace какого файла данных находится строка, и номер строки внутри блока.
- TYPE2 UNDO Это сегменты undo которые хранят данные перед изменениями для обеспечения транзакционной целостности: отмены транзакий, целостности чтения данных и обеспечения изоляции
- ROLLBACK сегменты rollback не должны использоваться в нормальном режиме работы начиная с версии 9i. Начиная с версии 9i используется автоматическое управление отмены операций основанное на сегментах TYPE2 UNDO (или просто undo). Всегда будет существовать один rollback сегмент для поддержки транзакций в момент создания БД (так как в момент создания ещё не существуют undo сегменты) но он не должен использоваться после создания БД
- Партиция таблицы( TABLE PARTITION) Таблица может быть разбита на несколько партиций. Если это настроено, то каждая партиция будет отдельным сегментом, а сама партицированная таблица не будет сегментом: она будет существовать как итог всех партиций. Каждая партиция будет таблицей, отдельным сегментом. Так как каждый сегмент может быть в отдельном табличном пространстве, то появляется возможность разбить таблицу между несколькими табличными пространствами
- Партиция индекса (INDEX PARTITION) по умолчанию индекс это один сегмента, но индексы как и таблицы могут быть партицированы. Если вы партицируете таблицу, обычно необходимо также партицировать и индекс
- Сегменты больших объектов (LOBSEGMENT, LOBINDEX, LOB PARTITION) Если столбец объявлен с типом large object, тогда в таблице хранится только указатель на запись в отдельном сегменте где хранятся данные этого столбца. Большие объекты могут быть индексированы для более быстрого доступа к данным внутри объекта и партицированы
- Кластер (CLUSTER) это сегмент которых содержит несколько таблиц. В отличие от партицирования которое позволяет распределять таблицы между разными сегментами, кластеризация позволяет собрать много таблиц в один сегмент
- Вложенные таблицы (NESTED TABLE) Если столбец внутри таблицы объявлен как определяемый пользователем объект (user defined object) который в свою очередь содержит столбцы, то такие столбцы хранятся в одельном сегмента, как вложенная таблица.
Каждый сегмент состоит из одного или более экстентов. Когда сегмент создаётся, Oracle выделяет инициализационный экстент в указанном табличном пространстве. Когда данные будет добавлятся экстент будет заполняться, и Oracle выделит другой экстент, в том же табличном пространстве, но не обязательно в том же файле данных. Если вы знаете что сегменту понадобится больше дискового пространства, вы можете вручную выделить экстент для этого сегмента. На рисунке 5-2 показано как определить расположение сегмента. Вначале создаётся таблица HR.NEWTAB используя параметры по умолчанию. Затем результат выполнения запроса к DBA_EXTENTS отображает, что сегмент состоит из одного экстента с номером ноль. Этот экстент находится в файле номер четыре и занимает 8 блоков. Первый из восьми блоков имеет номер 1401. Разме экстента 64 Кб, что говорит о том что размер блока 8 Кб. Следующая команда указывает Oracle что необходимо выделить ещё один сегмент для этого сегмента несмотря на то что первый экстент ещё не заполнен. Следующий запрос отображает что номер нового экстента равено единице, файл данных также с номером четыре и блоки выделены сразу после блоков первого экстента.
Отметим что из этого примера не совсем понятно из скольки файлов состоит табличное пространство, потому что алгоритм выбора файла для создания следующего экстента не просто очередь. Если табличное пространство состоит из нескольких файлов данных вы может указать в каком конкретно файле выделить экстент используя следующий синтаксис
ALTER TABLE tablename ALLOCATE EXTENT STORAGE (DATAFILE ‘filename’);
Последний запрос на рисунке 5-2 обращается к представлению DBA_DATA_FILES для нахождения имени файла в котором был выделен экстент, и название табличного пространства которому принадлежит файл данных. Для определения табличного пространства таблицы также можно использовать представление DBA_SEGMENTS.
Экстент состоит из набора последовательно пронумерованных блоков. У каждого блока есть область заголовок и область данных. Область заголовка имеет не фиксированный размер и записывается от начала блока. Помимо прочего, заголовок содержит информацию о строках (откуда в блоке начинается каждая строка) и информацию о блокировках. Область данных заполняется с конца блока. Между этимя двумя областями может быть (или не быть) пустое место. Событиями которые приведут к увеличению области заголовка является вставка данны и блокировка строки. Область данных вначале пусткая и затем заполняется по мере того как записываются новые строки (или ключи индекса если это блок сегмента индекса). Пусте пространство будет фрагментировано по мере вставки, удаления и изменения (что может привести к изменение размера строки) строк, но это не важно так как все операции с данными производятся в кэше буфера. Фрагментированное пространство объединяется когда это необходимо, обычно перед записью блока назад в файл данных процессом DBWn.
Для работы с данными большого объема СУБД Oracle предоставляет типы данных BLOB, CLOB, NCLOB и BFILE. Здесь LOB означает large object, или большой объект, и далее по тексту термины LOB и "большой объект" взаимозаменяемы. По сути, большой объект - это абстрактный тип для манипуляции данными большого объема внутри БД, а типы BLOB, CLOB, NCLOB и BFILE - его конкретные реализации.
Указанные типы данных можно использовать в СУБД Oracle для определения столбцов таблиц, атрибутов объектных типов и переменных PL/SQL.
Вот краткая характеристика этих типов:
- BFILE (от binary file) - данные хранятся во внешнем по отношению к БД файле, а значение типа BFILE содержит указатель на файл; данные считаются двоичными.
- BLOB (от binary large object) - данные хранятся в базе данных в отдельном сегменте * , а значение типа BLOB содержит указатель на них (LOB locator); данные считаются двоичными.
- CLOB (от character large object) - данные хранятся в базе данных в отдельном сегменте * , а значение типа CLOB содержит указатель на них (LOB locator); данные интерпретируются как текст в кодировке базы данных (database character set).
- NCLOB (от national character large object) - данные хранятся в базе данных в отдельном сегменте * , а значение типа CLOB содержит указатель на них (LOB locator); данные интерпретируются как текст в национальной кодировке (national character set)
* По умолчанию LOB'ы размером до 4000 байт хранятся непосредственно в строках таблицы (в табличном сегменте), а LOB'ы большего размера - в отдельном сегменте (возможно, в отдельном табличном пространстве). Это поведение регулируется опцией ENABLE|DISABLE STORAGE IN ROW команд CREATE TABLE и ALTER TABLE .
Итак, по месту хранения LOB'ы делятся на
- внутренние (BLOB, CLOB, NCLOB), данные которых хранятся в БД, и
- внешние (BFILE), данные которых хранятся в файлах операционной системы,
а по содержанию на
- двоичные (BFILE и BLOB), для хранения данных в двоичных форматах, например, MP3, JPG, объектный код программ, и
- текстовые (CLOB и NCLOB), для хранения данных в текстовых форматах, таких как XML, HTML, JSON, обычный текст.
Oracle 11g, согласно документации, работает с внутренними LOB'ами размером до 2 32 -1 байт и с BFILE файлами размером до 2 64 -1 байт.
Для работы с LOB'ами cоздам таблицу со столбцами соответствующих типов:
Вместе с таблицей были созданы сегменты для хранения больших объектов:
Для столбца типа BFILE отдельный сегмент не создан - ведь данные этого типа хранятся во внешних файлах.
Значение типа LOB может быть
- NULL - неинициализировано, не содержит указателя на LOB,
- пустым (empty) - указатель на LOB указывает в никуда,
- непустым - указатель на LOB указывает на данные LOB'а.
Пустые LOB значения создаются функциями EMPTY_CLOB и EMPTY_BLOB :
Последний запрос демонстрирует два способа проверить, является ли LOB пустым. Запрос использует пакет DBMS_LOB , содержащий процедуры и функции для работы с LOB'ами.
Начиная с версии Oracle 9i в SQL и PL/SQL поддерживается неявная конвертация между (N)CLOB и VARCHAR2, что позволяет манипулировать значениями в (N)CLOB столбцах и переменных так, как будто это значения типа VARCHAR2:
Как видим, функции и операторы, работающие с VARCHAR2, перегружены для типа (N)CLOB! При этом преодолеваются ограничения в 4000 символов, свойственные SQL типу VARCHAR2:
А вот операторы сравнения для (N)CLOB работают только в PL/SQL и не работают в SQL:
Выше я воспользовался функциями TO_NCLOB и TO_CLOB для явной конвертации значений VARCHAR2 в значения (N)CLOB. В следующей таблице представлены все функции для конвертации в LOB типы и обратно:
Функция | Где работает |
---|---|
TO_CLOB(character_data) | SQL и PL/SQL |
TO_BLOB(raw_data) | SQL и PL/SQL |
TO_LOB(long_data) | SQL and PL/SQL |
TO_NCLOB(character_data) | SQL и PL/SQL |
TO_RAW(blob_data) | только PL/SQL |
Как видим, функция TO_RAW недоступна в SQL и, отсюда, возможности конвертации между BLOB и RAW в SQL ограничены. Например:
Зато в PL/SQL работают явная и неявная конвертации между BLOB и RAW:
Рассмотренные возможности по работе со значениями LOB как с VARCHAR2 получили название SQL семантика для LOB'ов (SQL semаntics for LOBs). С их использованием связаны некоторые ограничения, как мы увидим ниже.
С точки зрения PL/SQL большие объекты делятся на:
- временные (temporary), время жизни которых не превышает сеанса работы с СУБД,
- постоянные (persistent), которые хранятся в базе данных или во внешнем файле.
- создаются либо с помощью DBMS_LOB.CREATETEMPORARY , либо простым присваиванием значения LOB переменной в PL/SQL коде,
- располагаются на диске во временном табличном пространстве (temporary tablespace),
- могут быть проверены с помощью DBMS_LOB.ISTEMPORARY ,
- освобождаются с помощью DBMS_LOB.FREETEMPORARY , что приводит к инвалидированию указателя на LOB,
- в отличие от постоянных, изменяются без создания записей в журнале БД (logging) и не контролируются транзакциями,
- могут быть скопированы в постоянные LOB'ы c помощью DBMS_LOB.COPY .
В вышеприведенных примерах с PL/SQL мы имели дело с временными LOB'ами.
Для работы с постоянными LOB'ами в PL/SQL нужно сначала получить указатель на LOB, а затем с его помощью извлекать или изменять данные, используя пакет DBMS_LOB . Следующий пример демонстрирует получение постоянного LOB'а и его потерю(!) при попытке изменить его значение простым присваиванием:
Дело в том, что SQL семантика для LOB'ов всегда порождает временные LOB'ы - это и есть то ограничение, о котором я упоминал выше. Неявное приведение VARCHAR2 к LOB (строка 7) или функция, перегруженная для (N)CLOB (строка 14), дают нам временные LOB'ы. Как только переменной PL/SQL, указывающей на постоянный LOB, присваивается временный LOB, переменная начинает указывать на временный LOB. А связь переменной с постоянным LOB'ом утрачивается.
Значение временного LOB'а можно сохранить в БД - и тем самым сделать постоянным - либо с помощью SQL либо, как уже упоминалось, с помощью DBMS_LOB.COPY . Продемонстрирую обе возможности:
Обратите внимание, что процедура DBMS_LOB.COPY заменила в постоянном NCLOB c3 только фрагмент, равный по размеру значению исходного NCLOB'а c2 . Как вариант, можно было перед копированием очистить LOB назначения с помощью DBMS_LOB.ERASE .
Изменения внутренних постоянных LOB'ов (в отличие от внешних или временных) в СУБД Oracle подчиняются транзакциям. Убедимся в этом, отменив только что сделанные изменения:
Типичный алгоритм для чтения или изменения постоянного LOB'а с помощью PL/SQL таков:
- Извлечь указатель на LOB из столбца таблицы с помощью SELECT .
- Открыть большой объект с помощью DBMS_LOB.OPEN .
- Получить оптимальный размер фрагмента для чтения (записи) LOB с помощью DBMS_LOB.GETCHUNKSIZE
- Получить размер LOB'а в байтах (для BLOB и BFILE) или символах (для CLOB и NCLOB) с помощью DBMS_LOB.GETLENGTH .
- Многократно вызывать DBMS_LOB.READ для чтения последовательных фрагментов LOB'а, пока не будут извлечены все данные
ИЛИ
многократно вызывать DBMS_LOB.WRITE , со смещением, или DBMS_LOB.WRITEAPPEND или иные процедуры DBMS_LOB для записи фрагментов данных. - Закрыть LOB с помощью DBMS_LOB.CLOSE .
В предыдущем примере с DBMS_LOB.COPY я не открывал и не закрывал постоянный LOB при помощи DBMS_LOB.OPEN и DBMS_LOB.CLOSE , однако, это стоит делать для улучшения производительности при изменениях больших объектов.
Приведу пример выгрузки данных из постоянного CLOB'а во внешний файл. Для доступа к внешним файлам потребуется создать директорию, например:
Следующий код выгружает содержимое столбца lobs_tab.clob_col в файл clob_col1.txt , используя пакет DBMS_LOB для чтения CLOB и пакет UTL_FILE для записи во внешний файл:
Альтернативно, можно выгрузить CLOB во внешний файл, пользуясь SQL семантикой для LOB и не прибегая к DBMS_LOB :
Для обратной операции - загрузки содержимого файла в LOB - также можно воспользоваться пакетами UTL_FILE и DBMS_LOB , циклически читая данные из файла и записывая в LOB. Но интереснее сделать это с помощью типа данных BFILE.
Тип данных BFILE содержит указатель на внешний файл, который
- состоит из двух частей: имя директории и имя файла,
- создается с помощью функции BFILENAME , например, BFILENMAE('FILES_DIR', 'novel.txt') ,
- может указывать на несуществующий файл.
Пакет DBMS_LOB позволяет читать содержимое BFILE, но не изменять его. Чтение из BFILE возвращает двоичные данные как тип данных RAW. Для преобразования в VARCHAR2, при необходимости, используется функция UTL_RAW.CAST_TO_VARCHAR2 .
Пример чтения BFILE и записи во временный BLOB:
В примере BFILE открывается и закрывается с помощью OPEN и CLOSE , аналогично внутренним LOB'ам. Также, пакет DBMS_LOB содержит несколько процедур и функций специально для работы с объектами BFILE:
Процедура / Функция | Что делает |
---|---|
FILEGETNAME | возвращает имя директории и файла BFILE |
FILEEXISTS | проверяет, что файл BFILE существует |
FILEOPEN | открывает файл BFILE |
FILEISOPEN | проверяет, что файл BFILE открыт |
FILECLOSE | закрывает файл BFILE |
FILECLOSEALL | закрывает все открытые в сеансе файлы BFILE |
Вместо чтения BFILE по частям пакет DBMS_LOB позволяет
- с помощью LOADCLOBFROMFILE загрузить содержимое BFILE в CLOB, указав, какую кодировку (набор символов) имеет содержимое,
- с помощью LOADBLOBFROMFILE загрузить содержимое BFILE в BLOB.
Пример загрузки текстового файла во временный CLOB (аналогично можно загрузить и в постоянный CLOB):
Значения src_offset и dest_offset отличаются, поскольку первое, для BFILE, выражено в байтах, а второе, для CLOB, выражено в символах. В файле и CLOB'е имеются девять двухбайтовых русских букв - напомню, их содержимое начинается с " привет, мир ".
Приведу неполный список процедур и функций DBMS_LOB для чтения, анализа и изменения значений BLOB, CLOB и NCLOB:
Процедура / Функция | Что делает |
---|---|
APPEND | добавляет один LOB в конец другого |
COPY | копирует все или часть содержимого LOB'а в другой LOB |
ERASE | удаляет все или часть содержимого LOB'а |
GETLENGTH | возвращает размер LOB'а |
INSTR | ищет "подстроку" в LOB'е |
ISOPEN | проверяет, открыт ли LOB |
ISTEMPORARY | проверяет, временный ли LOB |
READ | читает данные LOB'а |
SUBSTR | получает "подстроку" из LOB'а |
TRIM | сокращает размер LOB'а до указанного |
WRITE | записывает данные в LOB |
WRITEAPPEND | записывает данные в конец LOB'а |
Следующий эксперимент покажет разницу между внутренними и внешними постоянными LOB'ами. Помещу в поле bfile_col таблицы lobs_tab объект BFILE и скопирую единственную строку таблицы во вторую строку:
Команда INSERT привела к тому, что значения bfile_col в обеих строках связаны с одним и тем же внешним файлом, и его изменение отразится на обоих значениях.
А вот значения столбцов clob_col , nclob_col и blob_col для строк 1 и 2 стали независимы - не только указатели на LOB, но и данные внутренних LOB'ов в LOB-сегментах были скопированы. Продемонстрирую их независимость, изменив значения clob_col и nclob_col для строки 2:
Аналогично, при присваивании BLOB и (N)CLOB переменных в PL/SQL мы получаем независимые копии LOB'ов:
Итак, мы на примерах рассмотрели работу с большими объектами в SQL и PL/SQL. Работа с большими объектами имеет и другой аспект - это технология SecureFiles, позволяющая, в частности, сжимать хранимые в LOB-сегментах данные, свести к минимуму их дублирование, шифровать эти данные. Но эта тема выходит за рамки данного очерка.
Сжатие (Compression)
Другой возможностью SecureFiles является сжатие. Можно сжимать содержимое LOB-объектов, используя следующие SQL-предложение:
Сейчас, если выполнить PL/SQL-блок, вычисляющий объем:
то увидим, что значение used_bytes сейчас равно 1,646,592, или около 1,5 MB, что существенно меньше 5 MB.
Сжатие отличается от дедупликации. Сжатие происходит внутри LOB-столбца, в строке – каждый LOB-объект сжимается независимо от других. При дедупликации проверяются все строки, повторные значения удаляются и заменяются указателями. Если есть две существенно отличающиеся строки, дедупликация не уменьшит занимаемый размер, а сжатие может оптимизировать место, занимаемое LOB-объектами. Можно как сжимать, так и дедуплицировать данные.
Сжатие требует работы CPU, поэтому в зависимости от количества сжимаемых данных, сжатие может потерять смысл. Например, имеется много изображений в формате JPEG, которые уже сжаты, поэтому дальнейшее сжатие не уменьшит занимаемое место. С другой стороны, если CLOB-объектом является XML-документ, то сжатие может получиться существенным. Процесс SecureFiles-сжатия автоматически определяет, сжимаются ли данные или только расходуется процессорное время.
Индексы Oracle Text могут быть созданы как LOB-ы сжатых SecureFiles (compressed SecureFiles LOBs). Это главное преимущество хранения неструктурированных данных в базе данных Oracle по сравнению сжатыми файлами файловой системы.
Так же отметим, что сжатие LOB-объектов не зависит от сжатия таблиц. Если сжимается таблица CONTRACTS_SEC, то её LOB-объекты не сжимаются. Сжатие LOB-объектов будет происходить только при использовании приведенного выше SQL-предложения.
В Oracle Database 11g R2 есть третья возможность сжатия в дополнение к HIGH и MEDIUM: LOW. Как следует из её имени, в этом случае коэффициент сжатия минимальный, но намного меньше потребление ресурсов CPU, а также более высокая скорость процесса. В этом случае используется блок-базируемое сжатие без потерь (block-based lossless compression), подобное быстрому алгоритму LempelZivOberhumer (LZO) .
Рассмотрим пример LOW-сжатия таблицы, содержащей SecureFiles:
Если опустить фразу LOW, то по умолчанию сжатие будет выполнено в варианте MEDIUM. LOW-сжатие можно указать не только при создании таблицы; также можно применить LOW-сжатие, чтобы изменить существующий столбец.
Рассмотрим пример с этой же таблицей и столбцом. Для начала мы изменим столбец как несжатый:
Далее установим для столбца low-сжатие:
Однократное хранение нескольких одинаковых объектов (deduplication)
Дедупликация, вероятно, самая яркая возможность SecureFiles, поскольку из всех преимуществ файлов операционной системы перед внутренними BLOB-объектами она наиболее востребована. Допустим, в таблице хранится пять записей, каждая с BLOB-объектом. Три из них одинаковы. Если была бы возможность однократного хранения BLOB-объекта и размещения ссылки на него в других двух записях, это существенно бы уменьшило занимаемое место. Это возможно для файлов операционной системы, но не для LOB-объектов в Oracle Database 10g. Для SecureFile это легко реализуется с помощью свойства дедупликации. Его можно определить при создании таблицы или позднее:
В процессе дедупликации СУБД хеширует значения столбцов в каждой строке и сравнивает хеш-значения друг с другом. Если хеш-значения совпадают, то сохраняются они, а не исходный BLOB-объект. Когда добавляется новая запись, то вычисляется хеш, и если он совпадает со значением в другой строке, то сохраняется хеш-значение, в противном случае сохраняется реальное значение.
Теперь давайте определим объем пространства, сохраненного в результате дедупликации.
Определение занимаемого пространства LOB-сегментом можно выполнить с помощью пакета DBMS_SPACE. Ниже демонстрируется пример программы, показывающей занимаемое место:
Этот скрипт показывает объем занимаемого LOB-объектами пространства. Вот результат до процесса дедупликации:
и после дедупликации:
В приведенных данных достаточно сравнить только одну метрику used_bytes, которая показывает точное количество байтов, занимаемых LOB-столбцом. До дедупликации он занимал 4,923,392 байтов, или около 5 Мбайт, а уменьшился до 57,344 байт, что составляет около 57 Кбайт, то есть всего лишь около одного процента от исходного размера. Так получилось потому, что процесс дедупликации 100 раз нашел строки с одним и тем же значением (помните, мы в LOB-столбец всех строк поместили одно и тоже значение) и сохранил его только в одной строке, а в остальных – только указатели.
Можно обратить результат дедупликации:
Посмотрим после этого снова на занимаемое место:
Мы видим, что значение USED_BYTES выросло до исходной величины около 5 Мбайт.
Журналирование (Logging)
Журналирование определяет, как изменения данных в LOB-объектах записываются в поток redo-журнала. По умолчанию для них установлено полное журналирование, как для всех остальных данных. Но, поскольку данные в LOB-объектах обычно велики, вероятно, захочется в некоторых случаях отключить журналирование. Фраза NOLOGING, использованная в предыдущем примере, делает именно это.
Для SecureFiles имеется еще одно значение для этой фразы — filesystem_like_logging— как показано ниже:
Отметим, что выделенная жирным шрифтом строка, включает ведение redo-журнала для метаданных LOB-объектов, но не для самих LOB-объектов. Это похоже на файловую систему, когда метаданные файлов записываются в журналы файловой системы. Эта возможность облегчает восстановление после сбоев.
Мы рассмотрели процесс взаимодействия экземпляра и сессий: процессы и структуры памяти. В этой главе мы будем рассмотривать саму БД. Все процессы обработки информации происходят в памяти экземпляра БД, но хранение данных происходит в файлах базы данных на диске. База данных состоит из трех типов файлов: файл контроля, файлы логов и файлов даных. Данные хранятся в файлах данных.
Пользователи никогда не видят физический файл данных. Они видят логические сегменты. Системные администраторы ничего не знают о логических сегментах – они видят файлы. В базе данных Oracle физическая структура абстрагирована от логической. Это одно из требования парадигмы реляционных баз данных. Как DBA вы должны знать связь между логической и физической структурой БД. Мониторинг и администрирование этих структур – задача часто называемая как управление пространством (space management) является большой частью работы DBA. Средства предусмотренные в последних версиях БД могут автоматизировать задачу управления пространством в определенной степени, и они безусловно позволяют DBA настроить хранилище таким образом, чтобы максимально облегчить задачу обслуживания сервера.
Данные логически хранятся в сегментах (обычно таблицах), физически в файлах данных. Табличное пространтсво абстрагирует эти два понятия: в одном табличном пространтсве может храниться несколько сегментов и состоять из нескольких файлов данных. Нету прямой взаимосвязи между сегментом и файлом данных. Файлы данных могуть быть как файлами в файловой системе или (начиная с версии 10g) устройствами Automatic Storage Management (ASM).
Шифрование (Encryption)
Перед проведением шифрования необходимо установить крипто-блокнот (encryption wallet). (Полное описание encryption wallet можно найти в Oracle Magazine в моей статье «Transparent Data Encryption»
Кратко перечислим основные действия:
- Установить, если еще не задан, в файле sqlnet.ora параметр, определяющий расположение крипто-блокнота: Директория /opt/oracle/orawall уже должна существовать, в противном случае ее необходимо создать.
- Создать крипто-блокнот: Это предложение создает крипто-блокнот с паролем mypass и открывает его.
- Предыдущие два шага выполняются только один раз. После того, как крипто-блокнот создан и открыт, он остается открытым, пока работает база данных (до тех пор, пока она полностью не завершит работу). Если база данных перезапускается, необходимо открыть wallet предложением:
Если LOB-столбец SecureFile показан как зашифрованный, то шифруются все значения этого столбца во всех строках этой таблицы. После шифрования нельзя использовать обычный (Conventional Export or Import) экспорт и импорт этой таблицы, а необходимо использовать утилиту Data Pump.
Рассматривается использование следующего поколения LOB-объектов: SecureFiles (сохраняемые файлы), которые объединяют лучшее качества внешних файлов (external files) и LOB-объектов базы данных для хранения неструктурированных данных, которые допускают также шифрование, сжатие, однократное хранение нескольких одинаковых объектов (deduplication – дедупликация) и т.д.
Особенности очистки табличного пространства, занимаемого LOB объектами
В отличие от обычных таблиц удаление данных из таблицы с LOB не освобождает табличное пространство, занимаемое LOB. Для освобождения табличного пространства используется команда SHRINK либо TRUNCATE таблицы или (что более эффективно) TRUNCATE секции для секционированных таблиц.
Сжатие пространства для не секционированной таблицы осуществляется по команде
Для секционированной таблицы команды с shrink и truncate имеют вид:
Фраза UPDATE GLOBAL INDEXES в TRUNCATE обеспечивает исправность глобальных индексов после очистки секции по Truncate.
Модификация атрибутов конструкции STORE
Ряд атрибутов STORE могут быть добавлены или модифицированы в любой момент после создания таблицы командой ALTER TABLE (не модифицируются такие атрибуты как CHUNK и ENABLE/DISABLE STORAGE IN ROW).
Например, для столбца XMLIN таблицы SERVICEMSGXML модификация атрибутов NOCACHE на CACHE осуществляется так же по команде ALTER
Для режима STORE AS SECUREFILE можно модифицировать или добавлять новые атрибуты. Например, добавить DEDUPLICATE и модифицировать COMPRESS с LOW на HIGH по команде:
Кеширование (Caching)
Возможность кеширования – одно из преимуществ хранения неструктурированных данных в файлах операционной системы, а не во внутренних объектах базы данных. Файлы могут кешироваться в файловых буферах операционной системы. Внутренние объекты базы данных могут кешироваться базой данных. Тем не менее, в некоторых случаях кеширование может снизить производительность. LOB-объекты обычно очень велики (отсюда и название Large OBjects) и, если они попадают в кеш, то большинство количество других блоков будут оттуда вытеснены, чтобы дать место поступившему LOB-объекту. LOB-объект, возможно, и не будет потом использоваться, но при его записи в кеш используемые блоки оттуда будут удалены. Поэтому в большинстве случаев всё-таки следует отключить кеширование LOB-объектов.
В приведенном примере для CONTRACTS_SEC использовалась фраза nocache для отключения кеширования. Для включения кеширования следует изменить таблицу:
Это действие включает кеширование LOB-объектов. Отметим, что это кеширование относится только к LOB-объектам. Оставшаяся часть таблицы кешируется по тем же правилам, что и любая другая таблица, вне зависимости от того, установлено ли кеширование LOB-объектов таблицы, или нет.
Преимущества от кеширования сильно зависят от приложений. В приложении, работающем с мелкими (thumbnail ) рисунками, производительность, возможно, при кешировании увеличиться. Тем не менее, для больших документов или рисунков кеширование лучше отключить. Securefiles позволяют это контролировать.
Читайте также: