Как эффективно фильтровать большое количество записей на основе разрешений пользователей на конкретные записи с конкретными критериями? - PullRequest
0 голосов
/ 01 сентября 2018

Я работаю сопровождающим в устаревшей системе учета грузовых железнодорожных накладных на основе Java. Существует серьезная проблема с производительностью при получении списка накладных для отображения на их веб-сайте.

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

  • осталось 17 соединений
  • в нем есть огромное предложение where с 5 группами ИЛИ, чтобы определить, разрешен ли пользователю доступ к записи из-за определенного отношения к записи (грузоотправитель, грузополучатель, перевозчик, плательщик, супервизор) и проверить разрешение пользователя для доступа к записям, относящимся к конкретной железнодорожной станции
  • каждая группа OR имеет в среднем две exists() проверки с подзапросами на некоторые данные, относящиеся к записи, а также для проверки разрешения станции
  • при расширении для удобства чтения запрос имеет длину около 200 строк

По сути, доступность каждой записи для текущего пользователя, вошедшего в систему, зависит от следующих факторов: - компания пользователя - компания перевозчика, грузополучателя, грузоотправителя, плательщика каждой конкретной накладной - каждая накладная имеет несколько участков маршрута, и у каждого участка есть свой перевозчик и плательщик, поэтому требуются дополнительные условия контроля доступа, чтобы эти записи были видны пользователю - каждая накладная и каждый участок маршрута имеют станции отправления и назначения, и пользователю разрешено просматривать запись только в том случае, если ему был предоставлен доступ к любой из этих станций (с использованием простой таблицы отношений).

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

К сожалению, невозможно оптимизировать окончательный запрос перед его передачей в СУБД (точнее, Oracle 11g), поскольку система имеет сложную архитектуру и инструмент ORM для домашнего пивоварения, а окончательный запрос собирается в как минимум три разных места, которые отвечают за сбор полей для выбора, сбор объединений, добавление критериев, выбранных в пользовательском интерфейсе, и, наконец, причину этого вопроса - фильтр, связанный с разрешениями.

Я бы не сказал, что последний запрос очень сложен; напротив, он прост по своей природе, но он просто огромен.

Я боюсь, что решения для кэширования не будут очень эффективными в этом случае, потому что данные изменяются очень часто, и кэш будет перезаписываться каждую минуту или около того. Кроме того, из-за индивидуальных прав доступа каждый пользователь должен иметь собственный кэш, который необходимо поддерживать.

Помимо обычных рекомендаций, касающихся индексов и максимально возможной оптимизации каждого подзапроса, существуют ли другие известные решения для фильтрации большого количества записей на основе сложных правил доступа?

1 Ответ

0 голосов
/ 02 сентября 2018

Только мои два цента, поскольку я не вижу других ответов вокруг.

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

Хорошо, вы говорите, что в запросе осталось 17 соединений. Означает ли это, что в запросе есть одна главная таблица? Если так, то это первый раздел, который я бы оптимизировал. Ключевым аспектом является максимально возможное сокращение операций TABLE ACCESS BY ROWID для этой таблицы. Типичным решением является добавление хорошо настроенных индексов, чтобы максимально сузить INDEX RANGE SCAN в этой таблице, тем самым уменьшая выборки кучи.

Затем, при навигации по остальным [внешним] таблицам (предположительно, с использованием NESTED LOOPS) вы можете попытаться материализовать некоторые из этих условий в простые флаги 0/1, которые вы можете использовать, вместо целых условий.

Кроме того, если вам нужно только 20 строк, я ожидаю, что это будет очень быстро ... хорошо, если запрос правильно конвейеризован . Если в вашем случае это занимает слишком много времени, то это может быть не так. Вы сортируете / агрегируете / работаете с окнами по определенному условию, которое препятствует конвейерной обработке? Это условие может быть наиболее важным фактором для индексации, если вам просто нужно 20 строк.

Наконец, вы можете попытаться избежать выборки кучи, используя «индексы покрытия». Это действительно может повысить производительность вашего запроса, но я бы оставил его в качестве крайней меры, поскольку у него есть свои недостатки.

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

...