06.04.2011

Эффективная работа ограничений доступа к данным на уровне записей

В статье дается условное разделение ограничений прав доступа на уровне записей на простые и сложные; показано, как эти ограничения влияют на запрос к СУБД; даются рекомендации по написанию эффективных ограничений на уровне записей.

1. Режимы наложения ограничений

Существует 2 режима наложения ограничений на уровне записей. Первый, со словом РАЗРЕШЕННЫЕ в запросе, используется для исключения записей из результата выборки, которые пользователю запрещены (например, вывод списка документов). Второй, без слова РАЗРЕШЕННЫЕ, не включает фильтр для отсеивания запрещенных записей, но определяет поведение механизма работы с базой данных таким образом, чтобы при попытке доступа к запрещенным данным произошло исключение.

2. Различие между простым и сложным ограничением

Ограничения доступа на уровне записей задаются запросом, определяющим, какие записи пользователю доступны. В этом запросе всегда определена главная таблица, которая соответствует защищаемой таблице. Если таблица не указана (запрос может начинаться с "ГДЕ"), то это равносильно включению только одной таблицы в раздел ИЗ.

Ограничения доступа на уровне, задаваемые для объектов метаданных, можно разделить на 2 вида: простые и сложные. К простым относятся ограничения, которые имеют только одну таблицу в разделе ИЗ (и эта таблица – защищаемая). В этом случае ограничение доступа задается лишь с помощью реквизитов этой таблицы, без использования соединений с другими таблицами. Неявные соединения (обращение через точку к реквизиту ссылочного типа), добавляемые в запрос автоматически, переводят ограничение в категорию сложных. К сложному классу ограничений относятся запросы с более чем одной таблицей в разделе ИЗ.

Иногда ограничение, которое выглядит простым, на самом деле исполняется как сложное ограничение. Это случается, когда ограничение задано для регистра остатков или регистра бухгалтерии, поскольку в этом случае механизм работы с базой данных защищает не только таблицу движений этих регистров, но и таблицу остатков. Таким образом, запрос к таблице остатков получает ограничения, заданные для регистра. И чтобы эти ограничения включить в запрос к СУБД (чтобы иметь доступ к реквизитам регистра), механизм работы с базой данных добавляет таблицу движений в условие ограничений доступа.

3. Принципы трансляции ограничения доступа на уровне записей в запрос к СУБД

Рассмотрим самый простой случай, когда запрос выбирает данные из одной таблицы.

В случае, если запрос содержит слово РАЗРЕШЕННЫЕ, простое ограничение будет добавлено в раздел ГДЕ исходного запроса. Запрос к СУБД получит дополнительные инструкции по отбору только тех записей, которые разрешено видеть пользователю, и от СУБД придут только те данные, которые пользователю разрешены.

Запрос

Ограничение

Запрос к СУБД

ВЫБРАТЬ РАЗРЕШЕННЫЕ

   Код

ИЗ

      Справочник.Защищенный

ГДЕ КодДоступа = "1"

SELECT

   T1._Code

FROM

   _Reference8 T1

WHERE

      T1._Fld11 = N'1'

В случае, если запрос не содержит слова РАЗРЕШЕННЫЕ, запрос к СУБД строится по-другому. В таком запросе создается дополнительная колонка-индикатор, которая содержит признак, доступна или нет запись этой строки. Если какая-либо запись является неразрешенной, то механизм работы с базой данных прерывает исполнение запроса и создает исключительную ситуацию. Тем не менее, данные, доступные в этот момент, могут быть выведены в журнал регистрации, если настроена детальная регистрация доступа (событие ОтказВДоступе).

Запрос и ограничение

Запрос к СУБД

См. выше

SELECT

   CASE

         WHEN T1._Fld11 = N'1' THEN 0x01

         WHEN NOT (T1._Fld11 = N'1') THEN 0x00

   END,

   T1._Code

FROM

      _Reference8 T1

 

Сложные ограничения, включающие в себя другие таблицы (помимо той, которая защищается), участвуют в трансляции совершенно другим образом. И хотя принципы, описанные выше, остаются в силе, запросы со сложными ограничениями на уровне записей радикально усложняют результирующий запрос к СУБД, а, следовательно, его план (и, соответственно, время) исполнения.

Сложные ограничения доступа на уровне записей попадают в запрос к СУБД в виде подзапросов. Это означает, что СУБД исполняет подзапрос со сложными ограничениями для каждой потенциальной записи. Если сложных ограничений в запросе несколько (а некоторые из них могут быть добавлены неявно – при обращении через точку к реквизиту ссылочного типа), то для каждой из записей исполняется не один подзапрос, а больше: столько, сколько сложных ограничений включено в запрос к СУБД. Стоит отметить, что современные СУБД могут оптимизировать полученные запросы, и довольно часто оптимизация помогает сократить время исполнения запроса. Но иногда бывает так, что оптимизатор СУБД выбирает не самый оптимальный план, и запрос исполняется дольше, чем возможно.

4. Как написать эффективные ограничения доступа на уровне записей

Как было показано выше, сложные условия приводят к радикальному усложнению запроса. Если использовать простые ограничения на уровне записей, то запросы к СУБД с такими ограничениями будут проще и хорошо прогнозируются по времени исполнения. Поэтому рекомендуется реквизиты, от которых зависит доступность записей, включать в состав самого объекта конфигурации, а не обращаться к ним "через точку".

Кроме этого желательно индексировать реквизиты, которые используются в ограничениях доступа. Это дает возможность СУБД использовать индекс для отбора записей, соответствующих ограничению на уровне записей. Однако нужно заметить, что такие индексы эффективны лишь в случаях сравнения реквизита на равенство; если же сравнение происходит на больше или меньше или вхождение в диапазон, то каждый такой случай необходимо анализировать отдельно, и общую рекомендацию здесь дать затруднительно.