2. В хранимках, насколько я помню, все statements автоматически prepared (если это не запросы через EXECUTE — рекомендую от них полностью отказаться). Вы же не меняете запросы при каждом вызове хранимки, то зачем каждый раз составлять с нуля план?
3. CREATE OR REPLACE вполне достаточно. За счет версионности (атрибута «apiVersion» во входном json) новые хранимки поддерживают и старые форматы запросов / ответов, поэтому накатить их спокойно можно до обновления самого приложения
4. У нас одна схема, в ней 12 рабочих таблиц плюс еще 4 служебные. Никаких foreign ключей тут не требуется, т.к. обновление данных идет только в хранимках, там можно всю необходимую логику поддержать (например, обновлять данные сразу в нескольких таблицах)
Полностью согласен. Сейчас грамотный разработчик баз данных — на вес золота. Это отличный шанс для всех целеустремленных людей, не желающих почивать на лаврах былых достижений.
Прошлая команда три года не смогла сдвинуть проект с мертвой точки — все силы (и деньги) уходили на поддержание старой системы. Когда было предложено совершить рывок и вывести проект на новый уровень — вот и тогда «и решили отчалить от греха подальше.»
Спасибо, что неравнодушны к сервису — будем стараться оправдать ваши ожидания
Если лидер фронта говорит, что какая-то задача быстро реализуется средствами javascript, то никаких вопросов не возникает: сказал — сделал.
Чаще бывает так, что достаточно в ответ с бэка добавить один атрибут — и код на фронте уменьшается в 2 раза. Так почему это не сделать, потратив 30 минут на бэке и сэкономив десятки часов на фронте?
1. Прокси-сервис у нас на GoLang, он как раз занимается балансировкой запросов к Мастеру и Слйэвам, плюс обеспечивает взаимодействие с внешними сервисами
2. «Сохраненные запросы» — это VIEW вы имеете ввиду? Вьюшки мы используем только для внутренних целей (быстро получить данные напрямую из базы). Все запросы снаружи (от прокси-сервиса) идут через хранимки.
3. Деплой довольно простой, с помощью SQL-скриптов: сначала сохраняется текущий хранимок (это просто большой pgSQL-запрос на пару мегабайт), затем выполняем аналогичный pgSQL-запрос с новым кодом.
4. Данные хранятся в одной базе, с одним Мастером и несколькими Слэйвами (мультимастер пока не требуется), а сами хранимки — это фактически и есть микросервисы: каждая хранимка обрабатывает конкретный запрос фронта (например, получить список словарей, получить профиль пользователя, и т.д.). На выходе дает json со всеми необходимыми данными.
Мы планируем в сентябре выложить в публичный доступ шаблон такой системы — с простой и гибкой структурой данной, примером нескольких хранимок, с прокси-сервисом.
Мы просто показали альтернативный вариант. Принимать его или нет — решайте сами.
В PG типы внутри jsonb не описываются: можно из объекта получить нужные атрибуты, в виде json или строки, и дальше с ними работать. Непривычно, наверное, но получается достаточно удобно в итоге.
Это возможно, если хранимки будут работать с данными через SQL-запросы с поддержкой CTE (common table expresssions). Т.е. в рамках одного запроса вы работаете с разными таблицами, собираете данные, а на выходе упаковываете их в json.
Если пытаться обрабатывать данные в стиле PHP (сделал простой запрос, получил сырые данные в массив, обрабатываешь через множество циклов и условий и т.д.), то скорее всего код только вырастет
Естественно, и в нашем продукте есть ошибки — как и в любом другом продукте. Со своей стороны мы стараемся оперативно реагировать на запросы пользователей и исправлять баги.
Алексей, задача бэкенда очень простая — вернуть на фронт json с нужными данными, чтобы фронт эти данные показал пользователю. Желательно, чтобы это был один запрос, он выполнялся за несколько миллисекунд, и система обрабатывала тысячи параллельных запросов на недорогих серверах.
Если база данных все это может сделать, то зачем нужно обрабатывать данные в PHP и других языках? В сбалансированной системе каждый занимается своим делом: пироги печет пирожник (база данных обрабатывает данные и возвращает готовый json, а не сырые данные), а сапоги точит сапожник (PHP / Go взаимодействует с http-серверами и другими внешними ресурсами)
Любые данные из json вы можете сохранить в переменных, и использовать эти переменные в SQL-запросах. Главное — не делать запросы через EXECUTE — тогда и проблем не будет.
Отвечу сразу на все вопросы выше: данные пользователей были разбросаны по сотням таблиц, при этом никакой документации, как эти данные взаимосвязаны, не было. Поскольку эти структуры делала не одна команда, то получилось труднопроходимое болото(
Мы честно дебажили монолит из 1 млн. строк, пытаясь выстроить это болто осушить. В итоге более 99% данных пользователей мы смогли восстановить, что очень хорошо — мои первые оценки были не более 80%
Также стоит упомянуть, что всем пользователям, данные которых пострадали, был предоставлен бесплатный премиум.
Так функции на PHP тоже писали те разработчики, которые знали проект. То, что получилось в итоге много легаси и без документации — проблемы как организации работы, так и способов решения задач.
Никто не заставлял разработчиков делать 500 различных таблиц (сейчас всего 12, и их структура не меняется, хотя каждую неделю добавляется по несколько новых сущностей и фичей). Конечно, 500 таблиц сложнее вести, чем 12.
Никто не заставлял разработчиков обрабатывать данные в PHP и микросервисах: 1 млн строк кода сложно документировать, 30 тыс. строк гораздо проще.
Поэтому мы полностью поменяли философию разработки (как процесс, так и инструментарий), что иметь прозрачную систему и не плодить легаси и
В хранимках практически нет циклов, условий, рекурсий и т.д. 90% кода хранимки — это SQL-запрос, в другие языки это особо не перенесешь. Да, требуются определенные навыки дл их качественного написания / чтения / оптимизации, но это дело наживное.
У нас мало хранимок (около 100), в каждой 200-300 строк кода. В ближайших статьях я приведу примеры решения задачи на PHP и pgSQL — почувствуйте разницу
3. CREATE OR REPLACE вполне достаточно. За счет версионности (атрибута «apiVersion» во входном json) новые хранимки поддерживают и старые форматы запросов / ответов, поэтому накатить их спокойно можно до обновления самого приложения
4. У нас одна схема, в ней 12 рабочих таблиц плюс еще 4 служебные. Никаких foreign ключей тут не требуется, т.к. обновление данных идет только в хранимках, там можно всю необходимую логику поддержать (например, обновлять данные сразу в нескольких таблицах)
Я сторонник позиции «чем проще — тем надежнее»)
Спасибо, что неравнодушны к сервису — будем стараться оправдать ваши ожидания
Важный момент: хранимки стали эффективными буквально последние 2-3 года. 10+ лет назад они были совершенно бесполезными, особенно в PG.
Судя по количеству комментариев, интерес к теме большой — приступаю к написанию след. статьи на тему хранимок.
Чаще бывает так, что достаточно в ответ с бэка добавить один атрибут — и код на фронте уменьшается в 2 раза. Так почему это не сделать, потратив 30 минут на бэке и сэкономив десятки часов на фронте?
1. Прокси-сервис у нас на GoLang, он как раз занимается балансировкой запросов к Мастеру и Слйэвам, плюс обеспечивает взаимодействие с внешними сервисами
2. «Сохраненные запросы» — это VIEW вы имеете ввиду? Вьюшки мы используем только для внутренних целей (быстро получить данные напрямую из базы). Все запросы снаружи (от прокси-сервиса) идут через хранимки.
3. Деплой довольно простой, с помощью SQL-скриптов: сначала сохраняется текущий хранимок (это просто большой pgSQL-запрос на пару мегабайт), затем выполняем аналогичный pgSQL-запрос с новым кодом.
4. Данные хранятся в одной базе, с одним Мастером и несколькими Слэйвами (мультимастер пока не требуется), а сами хранимки — это фактически и есть микросервисы: каждая хранимка обрабатывает конкретный запрос фронта (например, получить список словарей, получить профиль пользователя, и т.д.). На выходе дает json со всеми необходимыми данными.
Мы планируем в сентябре выложить в публичный доступ шаблон такой системы — с простой и гибкой структурой данной, примером нескольких хранимок, с прокси-сервисом.
В PG типы внутри jsonb не описываются: можно из объекта получить нужные атрибуты, в виде json или строки, и дальше с ними работать. Непривычно, наверное, но получается достаточно удобно в итоге.
Если пытаться обрабатывать данные в стиле PHP (сделал простой запрос, получил сырые данные в массив, обрабатываешь через множество циклов и условий и т.д.), то скорее всего код только вырастет
Если база данных все это может сделать, то зачем нужно обрабатывать данные в PHP и других языках? В сбалансированной системе каждый занимается своим делом: пироги печет пирожник (база данных обрабатывает данные и возвращает готовый json, а не сырые данные), а сапоги точит сапожник (PHP / Go взаимодействует с http-серверами и другими внешними ресурсами)
Мы честно дебажили монолит из 1 млн. строк, пытаясь выстроить это болто осушить. В итоге более 99% данных пользователей мы смогли восстановить, что очень хорошо — мои первые оценки были не более 80%
Также стоит упомянуть, что всем пользователям, данные которых пострадали, был предоставлен бесплатный премиум.
Никто не заставлял разработчиков делать 500 различных таблиц (сейчас всего 12, и их структура не меняется, хотя каждую неделю добавляется по несколько новых сущностей и фичей). Конечно, 500 таблиц сложнее вести, чем 12.
Никто не заставлял разработчиков обрабатывать данные в PHP и микросервисах: 1 млн строк кода сложно документировать, 30 тыс. строк гораздо проще.
Поэтому мы полностью поменяли философию разработки (как процесс, так и инструментарий), что иметь прозрачную систему и не плодить легаси и
У нас мало хранимок (около 100), в каждой 200-300 строк кода. В ближайших статьях я приведу примеры решения задачи на PHP и pgSQL — почувствуйте разницу