Так вот из таких простых селектов потом и вырастает монолит на миллионы строк кода. И сервера жрет немеренно. Идея современного SQL — в том, чтобы писать эффективные запросы, причем достаточно быстро, отлаживать их, оптимизировать.
Дроблением на простые запросы этого не решишь — наоборот, только усложнишь разработку и производительность снизишь в десятки раз.
При работе с данными 90+% времени уходит на тестирование запросов: какие планы они используют, насколько быстро выполняются. Какие для этого есть средства в PHP?
Так никто и не мешает их банкам использовать. Хранимка — это такой же микросервис, с json-входом и json-выходом. Отличается о других только тем, что написан на SQL, а не PHP.
Не ставил целью изучить ИС банка: если Вы с ними работали, приведите аргументы, почему хранимки противопоказаны там.
1. Планировщик PG будет каждый раз ваш запрос перепланировать, тем более что там теперь два запроса.
2. Требуется прописывание доп. классов. Зачем? Завтра придут продакты, попросят еще 5 параметров включить. Будете класс переписывать? И все зависимости?
В моей случае это займет пару минут — в ответе дополнить 5 атрибутов.
3. А если запрос сложный, требуется получение данных из 5 таблиц, распаковка на лету json-данных из таблиц, использование этих данных в след. запросах?
Так никто и не запрещает пользоваться микросервисами на любом языке. Они должны дополнять друг друга, а не тянуть одеяло на себя.
В нашем проекте 95+% процентов задач бэка связаны именно с работой с данными, и для этих задач SQL подходит гораздо лучше любого не-SQL языка. Поэтому от PHP-кода в 1 млн строк осталось меньше 10К строк (и то почти весь на Go переписали)
Есть гипотеза, что множество других проектов также выиграют от такого маневра. Со своей стороны постараюсь наглядно показать его бенефиты
Прокси собирает GET/POST параметры, некоторые заголовки запроса (некоторые детали описываются в параметра мидлварок) и формирует из них json-структуру для запроса в хранимку, которая определяется роутером исходя из эндпоинта.
Статус ответа обычно 200 со структурой json и соответствующим Content-Type, описанной в документации, за исключением кейсов связанных неверным запросом или доступом (400/401/403). И конечно 5xx не исключение.
Сама хранимка отдает несколько больше полей в json для целей аналитики, прокси их вырезает и отправляет в сборщик аналитики в фоне, а на фронт летит то, что описано в документации ручки
Есть пара кейсов, где при помощи json описывается http-ответ, т.е. статус, заголовки и тело ответа.
В итоге PHP (или другой язык) просто дергает грамотный SQL-запрос, написанный специалистом. Вопрос ценности такой прослойки у меня и вызывает сомнения.
Я привожу конкретные примеры. Приведите, пжл, тоже примеры, когда использование PHP для обработки данных дает какие-либо преимущества.
В нашем случае необходимость в таком слое просто отпала. Система стала заметно проще и прозрачнее. Сейчас весь код бэкенда — это 200 микросервисов, из которых 180 — это хранимки.
SQL стал гораздо шире, чем просто SELECT/WHERE/GROUP BY
Поэтому сейчас и появилась возможность его активно использовать для 95+% задач по работе с данными. 10 лет назад не было для этого возможностей.
Не поленитесь, попробуйте сами одну-две функции на современном SQL написать. Это реально сдвиг сознания, что с данными можно по-другому работать.
Надеюсь, хватит сил в выходные написать статью с примерами хранимок (и самое главное с примерами их развития с учетом растущих требований проектов). Кидайте идеи, какую проблему будем решать (платежи, емейлинг, ...)
Совершенно верно! Приношу всем извинения, если ввел в заблуждение фразами типа «всю логику перенесли в базу». В базе только логика работы с данными через SQL.
Каждому языку есть своя ниша. Главное — использовать по назначению.
Глобальные константы — это конфиг. Необходимые компоненты вычитываются при запуске хранимки простым селектом.
Таблица юзеров — это скорее исключение, но и структура ее меняется достаточно редко (при условии использования jsonb-поля внутри). А по более специализированным таблицам — да, 3 — 10 хранимок, не больше.
Почему? Можно формировать ответ по запросу — буквально две строчки кода:
SELECT jsonb_object(key, jsrecord->(value))
FROM jsonb_each_text(ljAttrList)
Я ljAttrList кидаю маппинг (какие атрибуты с какими названиями вернуть), в jsrecord — атрибуты, которые хранимка использует.
Это поддержали, но по опыту не особо пригодилось: в API-документе прописаны нужные названия, их и придерживаемся. Надо добавить пару новых атрибутов — сразу в ответ и добавляем.
Насчет рефакторинга: если меняется структура какой-то таблицы, то достаточно обновить SQL-запросы только в тех хранимках, где эта таблица используется. Как правило, это не более 10 хранимок. Отсутствие доступа к таблицам вне хранимок заметно упрощает весь процесс.
Модель SQL-NoSQL позволяет вводить множество новых сущностей без изменения структуры — об этом расскажу в отдельной статье
Спасибо за пожелания) Но это слабый аргумент. Когда-то и без PHP обходились, а потом поняли его преимущества. Сейчас новый цикл пошел — поэтому и предлагаю немного пошире взглянуть на решение таких важных задач, как работа с данными.
Так я об этом и пишу: когда мы логику обработки данных перенесли в SQL, код стал 30К строк вместо 1 млн. строк. На PHP осталось около 10 микросервисов (и то их на Go переписали в итоге).
Валидацию параметров запроса прекрасно можно и SQL сделать — это не та операция, которая время и ресурсы занимает. Основные затраты идут именно на обработку.
Скажу честно, у меня не хватает фантазии, что остается для PHP. Давайте попробуем вместе найти — может, я заблуждаюсь…
Найти специалиста, который отлично знает и PHP, и SQL, заметно сложнее, чем специалиста, который отлично знает SQL.
Какие бенефиты может дать PHP-прослойка, чтобы платить двойную зарплату, увеличивать размер кода в 2+ раз (в дополнение к SQL писать еще и PHP), снижать скорость разработки в 2+ раз, плодить новых багов и т.д.?
Приведите примеры, когда это действительно необходимо. Я привожу примеры, когда без этого отлично можно обойтись
Чтобы любой проект не превратился в легаси, его надо регулярно рефакторить (т.е. переписывать довольно значительные куски кода). Проект растет, появляются новые сущности, меняется структура данных, меняются интерфейсы и т.д.
У нас такая процедура делается ежегодно, занимает 2-3 недели.
К примеру, есть два проекта: в одном 1 млн. строк кода, в другом 30 тыс. строк кода. В рамках рефакторинга обычно переписывается 20% кода (по нашей практике).
Вопрос: на какой из проектов потребуется меньше ресурсов?
Главный плюс, на мой взгляд, что в рамках одного SQL-запроса можно сразу сделать множество действий, что часто экономит 90+% ресурсов и времени.
Например, для выполнения какой операции надо сделать 10 действий. Сейчас в PHP делается 10 разных запросов, получаются сырые данные, потом как-то обрабатываются. Альтернатива — все это сделать в одном запросе:
1. Сначала из больших таблиц выбираются данные во временные таблицы (CTEs). Это делается строго один! раз
2. Далее работа идет с временными таблицами: они компактные, сидят в памяти
3. В концовке делаются необходимые обновления и формирование ответа.
Возьмите пример в своем проекте и попробуйте сделать через SQL — сами почувствуете разницу.
Здесь дело привычки, конечно. Единичные проекты требуют терабайтных баз с сотнями тысяч транзакций в секунду, но такие проекты и стоят много ярдов $ ))
Давайте начнем с того, что попробуем представить проект, в котором требуется более 3-х грамотных SQL-разработчиков. Я пока не смог такой представить — помогите в этом вопросе.
SQL-язык тем и хорош, что отлично подходит не только для написания запросов, но и для чтения этих запросов другими программистами. По нашему опыту, ввод грамотного разраба в тему занимает около месяца — затем он пишет качественные хранимки. Чем компактнее и понятнее ваш код, тем проще его и поддерживать, и развивать, и новых людей привлекать
Если микросервисы не лезут в базу, то какие тут могут быть проблемы? Все обновления в базе идут через хранимки, они выполняются внутри базы по транзакционной модели.
Приведите примеры, когда могут возникнуть проблемы целостности
Совершенно верно — об этом статья и написана. Обработка данных должна производиться базой данных, с помощью SQL. Зачем для этого городить прослойки? А взаимодействие с внешним миром — через микросервисы на любом удобном языке.
При рассылке почты основная проблема не в том, как отправить письмо, а в том, кому и что отправить. Вопросы, кому и что отправить, решаются на стороне базы (это и есть данные), а сам процесс отправки нужного текста на нужный адрес — это уже микросервис
Насчет потери разработчика: код в хранимках получается заметно компактнее, чем в не-SQL языках. SQL собственно для того и создан, чтобы не только писать запросы, но и понимать эти запросы. Вкупе с компактной структурой данных и комментами внутри хранимок войти в курс дела за 1 месяц для грамотного новичка реально — проверили на своем опыте.
Мне сложно представить проект, в котором для разработки хранимок требуется больше 3-х разработчиков, которые отлично знают SQL. Пришлите примеры таких проектов — давайте их обсудим.
1. В базу мигрировала бизнес-логика, связанная с обработкой данных (все, что можно сделать с помощью SQL). Другую логику переносить в базу данных нет смысла. Взаимодействие с внешними сервисами осталось в микросервисах, взаимодействие между базой и микросервисами — через прокси-сервис.
2. Для триггерных событий мы используем воркер на GoLang, который регулярно (раз в N секунд) дергает определенную хранимку в базе. А хранимка уже по нужному расписанию делает расчеты. Событие по дням рождения, к примеру, рассчитывает в ночные часы, когда нагрузка минимальна.
Приветственное письмо при регистрации отправляется сразу после регистрации: хранимка вместе с ответом фронту возвращает инструкцию для прокси-сервиса, что надо вызвать микросервис «emailing», чтобы он отправил письмо с таким-то текстом на такой-то адрес.
3. Используем, конечно. Например, надо отправить несколько миллионов пушей. За один раз это не сделаешь (внешний API не позволит), поэтому формируется в таблице заданий определенный пул, и по N заданий отправляется на обработку.
Также используем очередь на стороне микросервисов: например, после рассылки приходит миллион нотификаций о статусах доставки. Писать их в базе по одному очень накладно. Удобнее объединить в пакеты по 1000 и одним вызовом записать.
Все равно метаданные и объекты надо создавать. Как и ответ в формате json. В чем разница?
Как правило, у каждой хранимки свой запрос и свой ответ. При этом формат должен оставаться гибким, т.к. продукт постоянно растет, новые фичи каждый день вводятся.
Если сможете продемонстрировать, как с помощью объектов и метаданных сделать процесс работы с json удобнее, эффективнее и гибче, буду благодарен.