Задать вопрос
dubr
@dubr
пыхарь

Слой веб-приложения, объединяющий запросы к БД — такое бывает?

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

И вот под утро подумалось: а может что-то такое для сервера бывает? Вот есть у нас CMS или что-то типа, там есть блоки, которые друг про друга ничего не знают. Можно же сделать, чтобы запросы на данные из разных блоков (виджетов) не выполнялись сразу, а сначала собирались в кучу, потом как-то хитро группировались, выполнялись, и дальше уже данные отправлялись обратно в запросивший виджет. Примерно так:

// было
class Widget {
  public function actionFoo() {
    $news = News::where('id', 1)->one();
    echo $news ? $news['title'] : "ох =(";
  }
  public function actionBar() {
    $news = News::where('id', 2)->one();
    echo $news ? $news['title'] : "все плохо =(";
  }
}

// стало
class Widget {
  public function dataFoo() {
    return [ News::where('id', 1) ]
  }
  public function actionFoo($news) { 
    echo $news ? $news['title'] : "ох =(";
  }
  
  public function dataBar() {
    return [ News::where('id', 2) ]
  }
  public function actionBar($news) {
    echo $news ? $news['title'] : "все плохо =(";
  }
}


Соответственно, для этого примера магический слой должен выполнить запрос типа:
select * from news where id in (1, 2)
и вернуть результат, распиленный на две части.

Кто-нибудь думал в этом направлении? Или выгоды особой не будет? Или логику написать сложно? Или клиентский код получится неудобным?
  • Вопрос задан
  • 374 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 1
alexey-m-ukolov
@alexey-m-ukolov Куратор тега PHP
Самая большая проблема с этой системой - зависимые данные. Если в виджете 1 запрос А, работающий с таблицей X, зависит от данных из запроса Б к таблице Y (id сущностей оттуда берёт, например), то запрос Б нужно отправить сразу, не аггрегируя его с запросом В из виджета 2, который работает с теми же данными, но отправляется позже. Большинство запросов зависят друг от друга, поэтому ощутимой пользы такая штука не принесёт.

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

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

Плюс, виджеты, которые работают с одними и теми же данными, встречаются не часто - система будет работать вхолостую.

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

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

На фронтенде и парадигма другая и с запросами проще (их легко различать по URL), поэтому такую штуку и сделать легче и меньше вероятность себе ногу отстрелить. Ну и задержки там значительно серьёзнее - сходить по сети на бэкенд и сходить на бэкенде в БД - это как слетать к Альфе Центавра и съездить на другой конец города, поэтому если есть возможность не летать, её стоит использовать.

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

Но вот реальный кейс, где я похожую систему реализовал и использую: есть программа на C++, постоянно делающая запросы к внешнему API. Это внешнее API устанавливает лимит на количество запросов в секунду, в который программа не всегда укладывается. Выходов два: ставить задержки перед запросами или агрегировать их в пакеты (API это поддерживает). Второе решение, очевидно, лучше с точки зрения скорости работы. Но я не реализовывал в нём анализ и объединение похожих запросов - это сложно сделать, легко накосячить, а профит будет относительно небольшой. Всю эту штуку удалось сделать только за счёт того, что все операции асинхронные и запросы выполняются через планировщик. На каком-нибудь стандартном php-проекте этого не добиться.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы