18 февр. 2011 г.

Проверка прав на уровне записи

Разборка одного случая, когда запрос под Администратором выполнялся значительно быстрее чем под обычным пользователем, показала, что вина лежит на дополнительном условии с вызовом функции G_SEC_TEST.

Появление UDF функции в секции WHERE запроса часто сводит с ума оптимизатор и приводит к ужасным планам. Если проверку на права доступа перенести на уровень клиента, внутрь датасета, сразу после считывания записи с сервера и перед копированием ее во внутренний буфер, то получим выигрыш в тех случаях, когда у пользователя есть права на большинство записей в результате выборки. В противном случае — перенос проверки на клиента породит избыточный трафик по сети.

Слаще ли хрен редьки выяснить можно только экспериментальным путем.

Вот, если бы заранее знать долю записей на которые у текущего пользователя есть/отсутствуют права...

13 комментариев:

Александр комментирует...

А G_SEC_TEST не заменяется стандартными BIN_AND и BIN_OR ?

Andrei комментирует...

Можно заменить:

G_SEC_TEST(z.aview, ingroup) <> 0

эквивалентно

BIN_AND(BIN_OR(z.aview, 1), ingroup) <> 0

но, у нас для группы Администраторы условия
вообще не подставляются в запрос, так что
можно оставить:

BIN_AND(z.aview, ingroup) <> 0

Однако, проблемы с искажением плана это не решит.

Александр комментирует...

А можно пример как из-за этого меняется план?

Andrei комментирует...

Это к Ал-ре в понедельник.

Александр комментирует...

Александра говорит, что план не менялся, а просто тормозило с G_SEC_TEST. Тогда я думаю нужно заменить ф-цию из UDF на встроенную. Плюс можно попробовать так ((BIN_AND(BIN_OR(z.aview, 1), ingroup) + 0 <> 0), тогда точно план не изменится

Andrei комментирует...

Не будем спорить по пустому. Менялся именно план. В одном случае из таблицы gd_document шло несколько сотен чтений, в другом -- 800 тыс. Такая элементарная функция, как G_SEC_TEST не может ничего замедлить. Ее выполнение -- это доли процента от общих затрат на вычисление нужной страницы, чтение страницы с диска, извлечение записи из страницы, анализ полей по условиям запроса, пересылку результата по сети.

Александр комментирует...

Тогда это баг FB в данном случае. Почему в данном случае должен меняться план, это например если бы использовали какой-нить coalesce и с ним менялся бы план выполнения...

Unknown комментирует...

При замене на BIN_AND-BIN_OR план остался таким же, как и при использовании G_SEC_TEST.

Andrei комментирует...

Естественно. Еще не хватало, чтобы оптимизатор вчитывался в имена функций.

flakekun комментирует...

вроде нет бага
просто при выполнении запроса делается не fetchall и под Админом вытягивается не все записи
а под пользователем, т.к. есть ограничение, то в буфер который отправляется клиенту не хватает записей из тех которые отправлялись Админу, и сервер сканирует выдачу дальше и дальше, вот и набирается 800000 записей из gd_document
как-то так

Александр комментирует...

Точнее не так, вы попробуйте выполнить два этих запроса в IBE где стоит параметр fetch all и разницы не будет. А то что выбиралось 800тыс записей без фильтра на клиент, так это наши проблемы.

Andrei комментирует...

Там не на клиента. Там в статистике запроса показывалось 800 т. чтений в одном случае.

Александр комментирует...

Сделайте fetch all, будет 800тыс. в обоих вариантах.

Отправить комментарий