Несколько Источников Данных В Интерфейсе — «Sql» На Стороне Клиента.

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

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



Несколько источников данных в интерфейсе — «SQL» на стороне клиента.
</p><p>

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

Так.



Постановка задачи

У нас есть два сервиса.

Их могло быть и больше, но, судя по предыдущей картинке, пусть будут для уверенности.

Услуги звонков и контактов .

Спасибо коллегам из CRM за интересное задание.

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

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



Несколько источников данных в интерфейсе — «SQL» на стороне клиента.
</p><p>

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

  • Антипаттерны PostgreSQL: давайте выполним тяжелое соединение со словарем
  • Антипаттерны PostgreSQL: навигация по реестру
  • SQL HowTo: написание цикла while непосредственно в запросе, или «Ээлементарный трехшаг»


Плохое решение №1: «отдай мне все»

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

И его действительно может быть много – только один могут быть сотни звонков .

А для сервиса задача «все отдать» совсем непростая, если есть данные за несколько лет работы.

Но зачем нам «все», если пользователь редко прокручивает дальше первой страницы ?

Неудачное решение №2: «тонкая расческа»

Значит, нам не нужно группировать контакты?.

Давайте тогда сделаем это запросить первую страницу (20 записей) у службы контактов , А для каждого интервала даты между «соседними» контактами, спросим, что в звонках и сразу получим количество.

Теперь представим, что все наши звонки (или их много) были хронологически «выше» первого контакта — что произойдет? А будут такие же тормоза в интерфейсе , как и в предыдущей версии.

Кроме того, мы или мы отправим много запросов в сервис (для каждого из интервалов), что создаст избыточную нагрузку.

Или мы отправим один запрос со списком всех интервалов , но это, очевидно, займет много времени.



Успешное решение №1: «чтение по сегментам»

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

Что делать дальше с двумя упорядоченными сегментами данных вполне очевидно — объединить( объединить заказы ) и отрезать ( предел ) из упорядоченных всех записей после ближайшего из «крайних» ключей от каждого из сервисов.



Несколько источников данных в интерфейсе — «SQL» на стороне клиента.
</p><p>

Например, в нашем примере оказалось, что клавиша времени последнего звонка соответствует только 15 из 20 прочитанных контактов.

О порядке остальных 5 контактов и других вызовов мы ничего сказать не можем, потому что "других вызовов" в обозримом пространстве нет - поэтому мы пока не можем их нарисовать .



Плохое решение №3: «Одно кольцо, чтобы править всеми»

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

Но с этим вариантом некоторые данные будут прочитаны снова снова и снова — именно те, которые мы отбросили на предыдущей итерации и не отобразили.

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



Несколько источников данных в интерфейсе — «SQL» на стороне клиента.
</p><p>



Плохое решение №4: «два ключа на стороне сервера»

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

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

Поскольку у нас есть серверный BL без сохранения состояния , то либо мы их не спасём, либо будем вынуждены их где-то городить отдельный государственный магазин .

Это можно сделать, но это совсем не просто:

  • сегменты должны храниться уникальным образом ключ экземпляра -выборов на странице
  • необходимый политика инвалидности эти данные со временем, чтобы память не «утекла»
  • работа с этим репозиторием подразумевает дополнительные накладные расходы на сериализацию -пересылка-десериализация


Успешное решение №2: «два ключа на стороне клиента»

Собственно, зачем нам все это выносить на серверную часть, если все нам нужны только данные о клиенте ?.

Оставим их там.

То есть именно те данные, которые «не были нарисованы», должны быть сохранены на клиенте (например, прямо в памяти вкладок, даже не в localStorage), пока нам не понадобится их отрисовать.

В нашем предыдущем примере вы получите что-то вроде:

  • читать 20 контактов и 20 звонков параллельно
  • звонки были «сгруппированы» в 5 записей
  • сделал 5 «групповых» звонков + 15 контактов
  • На складе осталось 5 невытянутых контактов
  • Чего-то не хватает до 20? мы запрашиваем! (контактов и звонков по 20, параллельно со своих «крайних» клавиш)
  • «задача сведена к предыдущей», только у нас уже 25 контактов на 20 звонков


Краевые случаи

По сути, единственный отрицательный эффект такого решения – это последний разыгранный "групповая" запись может "покрутить счётчик" , а мы дочитываем все новые и новые записи, «втекающие» в него.

К счастью, эта ситуация вполне положительно воспринимается в интерфейсе , потому что мы показываем пользователю: «Ой, всё хорошо, мы не умерли, не зависли, мы работаем!» Теги: #Алгоритмы #программирование #ERP-системы #sql #sql советы и рекомендации #sbis

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.