Наиболее эффективный дизайн для таблицы «последних 20» в Oracle? - PullRequest
2 голосов
/ 27 февраля 2012

В моей системе Users можно добавлять / редактировать / просматривать Customers.Я хотел бы добавить функцию, позволяющую пользователю видеть «Недавно просмотренные клиенты».Это покажет им последних 20 клиентов, которых они видели (включая добавление / редактирование).

Пользователи будут просматривать клиентов очень часто, когда они переходят между различными веб-страницами, и это должно быть очень эффективным.Я хотел бы сохранить это между сеансами, поэтому он должен быть сохранен в базе данных.Сейчас около 16 000 пользователей и 600 000 клиентов.

Вот то, что я считаю дизайном.

Создайте новую таблицу:

  • Столбцы (UserId, CustomerId, DateViewed)
  • Первичный ключ - (UserId, CustomerId)
  • Индекс организован
  • Отдельные индексы для внешних ключей UserId и CustomerId
  • DateViewed столбецсуществует только для упорядочения записей

Создайте процедуру PL / SQL, которая с параметрами UserId и CustomerId отвечает за сохранение того, что пользователь просмотрел клиента.В процедуре PL / SQL я бы:

  • Использовать MERGE, чтобы вставить или обновить строку с заданными UserId и CustomerId настройками DateViewed до SYSDATE
  • Если в результате слияния была вставлена ​​строка, используйте аналитический запрос для удаления любых строк с row_number()> 20

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

Скажем, раз в месяц удаляйте все записи с DateViewed старше года.Это было бы полное сканирование.Cascade удаляет из Customer и User в новую таблицу.

У кого-нибудь есть предложения по улучшению или другие идеи, которые стоит профилировать?

(Другая идея, которую я имел, состояла в том, чтобы денормализовать в таблицу с20 столбцов для различных идентификаторов CustomerId и случайных значений по сравнению с CustomerId1 -> CustomerId2 -> CustomerId3. Это потребует различных обновлений в зависимости от того, где CustomerId уже появился в списке.)

Ответы [ 2 ]

2 голосов
/ 27 февраля 2012

Полагаю, вы довольно тщательно продумали проблему.

Одна вещь, которую я бы предложил вам попробовать, - отложить обрезку 21-го (и более позднего) последнего из просмотренных клиентов для пользователя.Если вы это сделаете, вам нужно будет включить ТОП-20 в ваш запрос выбора.

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

В зависимости от того, насколько часто выполняется добавление / редактирование / просмотр клиента, может быть, что сокращение каждый развставка записи обходится дороже, чем сортировка и выбор ТОП-20. Вы можете выполнить обрезку как запланированную фоновую задачу, скажем, один раз в час или даже один раз в день.

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


Относительно вашей другой идеи (20 денормализованных столбцов): Это не рекомендуется!

1 голос
/ 27 февраля 2012

согласен со столбцами и первичным ключом;Я не согласен со стратегией индексирования.

Запрос, который вы хотите оптимизировать, будет выглядеть следующим образом:

 select customer_id, rn 
   from (select customer_id, rownum as rn
           from user_viewed_customer
          where user_id = :p_user_id
          order by date_viewed desc)
  where rn <= 20;

Лучший вариант для этого запроса - только индекс: (user_id, date_viewed desc, customer_id),Наличие организованной по индексу таблицы добавляет немного, как и индексы с одним столбцом на user_id и customer_id - индекс на user_id не нужен из-за индекса с несколькими столбцами, и индекс customer_id поддерживаетудаляет только каскадЯ удивлен, что вы действительно можете удалить клиентов;что происходит с остальными их историческими данными, когда вы делаете это?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...