А от шарповой версии запроса уже конкретно начинает течь кровь из глаз, при том, что простые запросы там прекрасны. В качестве примерна приведу получение всех записей, где определенное поле равно чему-то:
#mongodb
_mongoCollection.Find(record=>record.Field3=="qwerty123").ToList();
В примере используется трансляция в монговский формат внутришарпового языка запросов к коллекциям LINQ, потому всё максимально прозрачно.#mongodb
Примерно год назад я перетаскивал базу данных Палантира (чуть больше терабайта) с сервера на сервер. С помощью консольных утилит это было то ещё удовольствие, требующее как минимум стабильного соединения с сервером в течение многих часов.
В монге встроен механизм, который может быть использован в т.ч. для подобного переезда без отключения базы: создаём реплики на новых серверах, после чего постепенно отключаем старые инстансы и база перенесена.
В посгресе такого механизма "из коробки" нет. Но есть широко распространенное средство организации отказоустойчивых кластеров: Patroni. С год назад я к сожалению не осознавал, зачем оно мне.
Прилагаю статью с описанием процесса переноса продакшн базы без остановки доступа к данным. Кросивое.
Теперь надо бы для общего развития поднять кластер где-нибудь у себя.
#mongo
В монге встроен механизм, который может быть использован в т.ч. для подобного переезда без отключения базы: создаём реплики на новых серверах, после чего постепенно отключаем старые инстансы и база перенесена.
В посгресе такого механизма "из коробки" нет. Но есть широко распространенное средство организации отказоустойчивых кластеров: Patroni. С год назад я к сожалению не осознавал, зачем оно мне.
Прилагаю статью с описанием процесса переноса продакшн базы без остановки доступа к данным. Кросивое.
Теперь надо бы для общего развития поднять кластер где-нибудь у себя.
#mongo
В прошлом году итоги я подвёл в ноябре при запуске #палантир@eshu_coding, после него ничего особо интересного не было.
В этом году никаких проектов не под NDA, я в общем-то не делал. Если без подробностей, то вот краткие итоги личностного роста:
1. Научился готовить Tarantool, прошёлся по куче граблей, примерно понял, где он реально нужен, и главное, где не нужен. Пришлось поверхностно познакомиться и с механизмом построения кластеров: репликация, шардирование, вот это вот всё.
2. Нырнул в MongoDB на уровне, отличном от "положил как в помойку, достал по id/однострочному запросу". Многоступенчатые запросы, подписки на обновления коллекций, TTL, транзакции, materialised view. Впервые завел реплика-сет вместо отдельностоящего инстанса.
3. Построил пару обменников на RabbitMQ, пришло осознание проглоченного и применённого на коленке в 2021.
4. Влюбился в систему сбора метрик Prometheus. Если раскидать их по приложению и заодно подключить сбор с компонентов системы (баз данных и т.д.), получается крайне информативно. Дефолтный визуализатор так себе, но основные функции выполняет.
5. Познакомился с EKL стеком - сбор и визуализация логов. Особой любви не случилось, уж больно оно огромно и прожорливо. Можно кстати использовать ELK для построения красивых дашбордов по данным из Prometheus-а, но это мне пока не особо нужно.
6. Прогресс как шарписта у меня вышел так себе. Научился красиво описывать rest api с помощью Swagger, да в общем-то и всё. Ну ещё окончательно освоил разработку с использованием докера: приложение сразу запускается и отлаживается в контейнере, окружённое соседними сервисами. При прогоне тестов также активно использую песочницу, поднятую в docker-compose.
P.S. NoSQL я накушался досыта, 2023 - время вернуться к истокам - C# + PostgreSQL.
В этом году никаких проектов не под NDA, я в общем-то не делал. Если без подробностей, то вот краткие итоги личностного роста:
1. Научился готовить Tarantool, прошёлся по куче граблей, примерно понял, где он реально нужен, и главное, где не нужен. Пришлось поверхностно познакомиться и с механизмом построения кластеров: репликация, шардирование, вот это вот всё.
2. Нырнул в MongoDB на уровне, отличном от "положил как в помойку, достал по id/однострочному запросу". Многоступенчатые запросы, подписки на обновления коллекций, TTL, транзакции, materialised view. Впервые завел реплика-сет вместо отдельностоящего инстанса.
3. Построил пару обменников на RabbitMQ, пришло осознание проглоченного и применённого на коленке в 2021.
4. Влюбился в систему сбора метрик Prometheus. Если раскидать их по приложению и заодно подключить сбор с компонентов системы (баз данных и т.д.), получается крайне информативно. Дефолтный визуализатор так себе, но основные функции выполняет.
5. Познакомился с EKL стеком - сбор и визуализация логов. Особой любви не случилось, уж больно оно огромно и прожорливо. Можно кстати использовать ELK для построения красивых дашбордов по данным из Prometheus-а, но это мне пока не особо нужно.
6. Прогресс как шарписта у меня вышел так себе. Научился красиво описывать rest api с помощью Swagger, да в общем-то и всё. Ну ещё окончательно освоил разработку с использованием докера: приложение сразу запускается и отлаживается в контейнере, окружённое соседними сервисами. При прогоне тестов также активно использую песочницу, поднятую в docker-compose.
P.S. NoSQL я накушался досыта, 2023 - время вернуться к истокам - C# + PostgreSQL.
Telegram
Эшу быдлокодит
Палантир. Часть 24. Итоги, общая архитектура проекта.
#палантир@eshu_coding
По завершении ботов-агрегаторов проект я считаю завершенным, время описать что же получилось и подвести итоги.
На картинке:
DataFair - мастер сервер
DataLoader - сборщик
Пунтиром…
#палантир@eshu_coding
По завершении ботов-агрегаторов проект я считаю завершенным, время описать что же получилось и подвести итоги.
На картинке:
DataFair - мастер сервер
DataLoader - сборщик
Пунтиром…
👍9❤1
Ну чтож, надо посмешить богов, озвучить свои планы.
Чего хочу я в этом году:
1. Немного обмазаться фронтенд разработкой, но без фанатизма. Пока думаю о связке React + Typescript.
2. Попробовать на практике стандартную шарповую ORM: Entity Framework.
3. Углубиться в PostgreSQL, поиграться с уровнями изоляции транзакций, подтянуть оптимизацию запросов, возможно попробовать пособирать разные конфигурации кластеров на foreign table.
4. Прочитать несколько умных книжек, что-то типа:
a) Рихтер
b) Высоконагруженные приложения Фаулера
c) Ещё что-нибудь по архитектуре.
5. Начать подтягивать базу по Computer Science, мб копнуть алго задачи.
Вот такие планы, интересно, что исполнится к концу года:)
Чего хочу я в этом году:
1. Немного обмазаться фронтенд разработкой, но без фанатизма. Пока думаю о связке React + Typescript.
2. Попробовать на практике стандартную шарповую ORM: Entity Framework.
3. Углубиться в PostgreSQL, поиграться с уровнями изоляции транзакций, подтянуть оптимизацию запросов, возможно попробовать пособирать разные конфигурации кластеров на foreign table.
4. Прочитать несколько умных книжек, что-то типа:
a) Рихтер
b) Высоконагруженные приложения Фаулера
c) Ещё что-нибудь по архитектуре.
5. Начать подтягивать базу по Computer Science, мб копнуть алго задачи.
Вот такие планы, интересно, что исполнится к концу года:)
🔥7👍4👏2
Эшу быдлокодит
Ну чтож, надо посмешить богов, озвучить свои планы. Чего хочу я в этом году: 1. Немного обмазаться фронтенд разработкой, но без фанатизма. Пока думаю о связке React + Typescript. 2. Попробовать на практике стандартную шарповую ORM: Entity Framework. 3.…
Ну что же, фронтенд мой пока закончился на попытке нормально подружить Visual Studio и фронтенд разработку.
Я стремительно расширяю сознание в части строительства всякого интересного на базе MongoDB, скоро буду выходить на новый уровень в части работы с RabbitMQ.
PostgreSQL? Entity Framework? Фронтенд? Планирование? Не, это для лохов.
Я стремительно расширяю сознание в части строительства всякого интересного на базе MongoDB, скоро буду выходить на новый уровень в части работы с RabbitMQ.
PostgreSQL? Entity Framework? Фронтенд? Планирование? Не, это для лохов.
🔥3🤡2🤔1
Не прошло и 5 лет работы с с#, как я сподобился начать читать в режиме "от корки до корки" базовую книгу: Рихтера. Она несколько устарела: относится к версии языка от 2012 года. Но т.к. базовые концепции, лежащие в основе, с тех пор не поменялись, так что ознакомиться надо.
В начале (введение, общий обзор механики CLR, сборки проектов) ничего нового толком не было, я либо все знал, либо оно было мне уже не актуально. Но стоило дойти до конкретики - некоторые моменты, используемые мной годами, стали вставать на свои места.
Так, операцию сравнения - == между двумя экземплярами класса надо применять с осторожностью, результат зависит далеко не только от их содержимого.
При этом, если классы - это тип, полученный от другого объекта вызовом стандартного метода GetType - с ними такую операцию можно делать спокойно, теперь я знаю почему.
Во всех экземплярах классов хранится ссылка на объект-тип. GetType как раз ее и возвращает. Не то, чтобы что-то революционное, просто небольшой штрих в общей картине.
Далее здесь будет что-то типа конспекта, который буду писать по мере прочтения. Ну и будут новые теги:
#книги
#Рихтер
В начале (введение, общий обзор механики CLR, сборки проектов) ничего нового толком не было, я либо все знал, либо оно было мне уже не актуально. Но стоило дойти до конкретики - некоторые моменты, используемые мной годами, стали вставать на свои места.
Так, операцию сравнения - == между двумя экземплярами класса надо применять с осторожностью, результат зависит далеко не только от их содержимого.
При этом, если классы - это тип, полученный от другого объекта вызовом стандартного метода GetType - с ними такую операцию можно делать спокойно, теперь я знаю почему.
Во всех экземплярах классов хранится ссылка на объект-тип. GetType как раз ее и возвращает. Не то, чтобы что-то революционное, просто небольшой штрих в общей картине.
Далее здесь будет что-то типа конспекта, который буду писать по мере прочтения. Ну и будут новые теги:
#книги
#Рихтер
👍2
Практически осилил фундаментальную главу про типы. В целом - почти ничего нового, но пару занятных нюансов вычитал.
В с# есть разделение на типы - значимые (структуры, живут обычно в стеке) и ссылочные (обычные классы, живут в куче).
Для значимых сравнение между двумя экземплярами идёт по значению внутренностей, для классов - сравнивается эквивалентность ссылки.
Обычная практика - сделать структуру вида "координата", содержащую х, у и z и пользоваться ей.
Вычитал новое для себя, что дефолтные операторы сравнения значимых типов работают на базе рефлексии, что ни разу не быстро. Хочешь скорости - не забудь сам написать эти операторы.
Ещё из интересного - если выдавливать максимум производительности, то использовать штатные методы -ToString, GetType, GetHashCode для значимых типов стоит с осторожностью - легко наступить на грабли и засрать кучу мусором - во многих случаях сначала будет произведена операция упаковки (сама по себе не очень быстрая) значимого типа в кучу из стека, а потом уже вызван метод. Те из них, которые поддаются переопределению - переопределить. А GetType - использовать только по большой нужде. Кроме траты времени на упаковку мы нагружаем сборщик мусора, что в некоторых случаях даже печальнее.
Ну и бонусом, для совсем уж экономии на спичках - избегать виртуальных методов.
#книги
#рихтер
В с# есть разделение на типы - значимые (структуры, живут обычно в стеке) и ссылочные (обычные классы, живут в куче).
Для значимых сравнение между двумя экземплярами идёт по значению внутренностей, для классов - сравнивается эквивалентность ссылки.
Обычная практика - сделать структуру вида "координата", содержащую х, у и z и пользоваться ей.
Вычитал новое для себя, что дефолтные операторы сравнения значимых типов работают на базе рефлексии, что ни разу не быстро. Хочешь скорости - не забудь сам написать эти операторы.
Ещё из интересного - если выдавливать максимум производительности, то использовать штатные методы -ToString, GetType, GetHashCode для значимых типов стоит с осторожностью - легко наступить на грабли и засрать кучу мусором - во многих случаях сначала будет произведена операция упаковки (сама по себе не очень быстрая) значимого типа в кучу из стека, а потом уже вызван метод. Те из них, которые поддаются переопределению - переопределить. А GetType - использовать только по большой нужде. Кроме траты времени на упаковку мы нагружаем сборщик мусора, что в некоторых случаях даже печальнее.
Ну и бонусом, для совсем уж экономии на спичках - избегать виртуальных методов.
#книги
#рихтер
👍3
Сколько времени программисту нужно, чтобы разобраться с тем, как включить мультики с usb с телевизора?
15 минут и помощь системного аналитика, знающего бэкдор: направлять пульт строго в правый нижний угол телевизора.
15 минут и помощь системного аналитика, знающего бэкдор: направлять пульт строго в правый нижний угол телевизора.
😁5
Эшу быдлокодит
Практически осилил фундаментальную главу про типы. В целом - почти ничего нового, но пару занятных нюансов вычитал. В с# есть разделение на типы - значимые (структуры, живут обычно в стеке) и ссылочные (обычные классы, живут в куче). Для значимых сравнение…
Продолжаю читать про типы. Наткнулся на пару моментов, где я по незнанию лепил избыточный код:
1. Увидел как вызывать конструктор из другого конструктора. Чуть меньше копипасты:)
2. Узнал, что статический конструктор по умолчанию потокобезопасен. То есть все мои неэстетичные огородики с блокировками в таких конструкторах отправляются на помойку. Отлично.
#рихтер
#книги
1. Увидел как вызывать конструктор из другого конструктора. Чуть меньше копипасты:)
2. Узнал, что статический конструктор по умолчанию потокобезопасен. То есть все мои неэстетичные огородики с блокировками в таких конструкторах отправляются на помойку. Отлично.
#рихтер
#книги
👍4
Наткнулся на забавный вопрос к собеседованиям:
Как изменить в уже запущенной программе значение строковой константы?
Константа на то и константа, чтобы быть неизменной. Да ещё строки в c# неизменяемые, но есть обходной путь, правда череватый выстрелом даже не в ногу, а в живот.
В c# есть особый раздел языка: unsafe. По сути, это что-то вроде урезанного языка c++. И вот с помощью такой вставки можно получить указатель на место в памяти, где хранится эта константа инагадить записать туда свои байтики.
Потому родился встречный вопрос:
А у вас в кодовой базе такое практикуется?
Как изменить в уже запущенной программе значение строковой константы?
Константа на то и константа, чтобы быть неизменной. Да ещё строки в c# неизменяемые, но есть обходной путь, правда череватый выстрелом даже не в ногу, а в живот.
В c# есть особый раздел языка: unsafe. По сути, это что-то вроде урезанного языка c++. И вот с помощью такой вставки можно получить указатель на место в памяти, где хранится эта константа и
Потому родился встречный вопрос:
А у вас в кодовой базе такое практикуется?
🔥6
Forwarded from javawatch
ChatGPT достигла уровня человека! Я попросил ее написать пример использования модулей в C++23 через cmake, и у нее не получилось. У меня тоже не получилось. Каких высот мы достигли!
😁6🤡1
Познакомился с работой с координатами на карте. Широта и долгота, x и y, логично ведь? Север на карте - сверху, вертикаль - это y. А горизонталь - x.
А вот стандартная шарповая библиотека для работы с пространством считает иначе, придется с этим жить.
#csharp
А вот стандартная шарповая библиотека для работы с пространством считает иначе, придется с этим жить.
#csharp
Docs
Пространственные данные — EF Core
Использование пространственных данных в модели Entity Framework Core
А монга своей простотой однако развращает. После года плотной работы с ней, почти в любой ситуации, когда надо какое-то хранение состояния хочется просто насрать им записать его в монгу и пойти дальше.
На неделе надо было максимально быстро накидать незамысловатый UI для внутреннего пользования, так чтобы работало на Винде, посмотрел несколько вариантов реализации:
1. C# Win Forms
2. C# WPF.
3. C# MAUI
4. React.js
У Win Forms в наличии визуальный редактор: накидал элементов, сгенерировался c# код, чуть поправил его под себя - и готово.
У WPF - тоже есть редактор, но генерируется xaml разметка, что-то типа xml. Главная проблема, что его тоже нужно знать.
MAUI - тот же xaml. Не предполагает визуального редактора. Предлагаемый путь разработки - пересборка приложения на ходу, на живую: приложение запущено в дебаге, ты на ходу правишь xaml и смотришь результат. Заманчивой выглядит перспектива кроссплатформенности: одна и та же кодовая база собирается под Android, iOS и Windows. Главный недостаток MAUI - низкая распространенность. Изучать его имеет смысл если только для души.
React - это другой язык программирования - Java Script. Может быть собран в приложение под любую распространенную ОС, но основная точка приложения - веб сайты. Разработка идёт примерно как в MAUI: открыт браузер, меняется код - меняется внешний вид сайта.
В целом, наименьшее отвращение у меня вызвали React и MAUI. Но даже для решения простых задач в оба из них надо погружаться, это как минимум пара дней.
В итоге язажал нос и решил свою задачу на Win Forms за несколько часов, после чего пошел дальше. Но с реактом я когда-нибудь разберусь!
1. C# Win Forms
2. C# WPF.
3. C# MAUI
4. React.js
У Win Forms в наличии визуальный редактор: накидал элементов, сгенерировался c# код, чуть поправил его под себя - и готово.
У WPF - тоже есть редактор, но генерируется xaml разметка, что-то типа xml. Главная проблема, что его тоже нужно знать.
MAUI - тот же xaml. Не предполагает визуального редактора. Предлагаемый путь разработки - пересборка приложения на ходу, на живую: приложение запущено в дебаге, ты на ходу правишь xaml и смотришь результат. Заманчивой выглядит перспектива кроссплатформенности: одна и та же кодовая база собирается под Android, iOS и Windows. Главный недостаток MAUI - низкая распространенность. Изучать его имеет смысл если только для души.
React - это другой язык программирования - Java Script. Может быть собран в приложение под любую распространенную ОС, но основная точка приложения - веб сайты. Разработка идёт примерно как в MAUI: открыт браузер, меняется код - меняется внешний вид сайта.
В целом, наименьшее отвращение у меня вызвали React и MAUI. Но даже для решения простых задач в оба из них надо погружаться, это как минимум пара дней.
В итоге я
👍4😁3
Есть такой продукт для обмена данными между микросервисами - RabbitMQ, я его неоднократно упоминал в канале выше. Это - брокер сообщений, вся суть его - передача информации из входной точки (обменника) к выходным (очереди), на которые подписываются сервисы. RabbitMQ поддерживает гарантированную доставку сообщения. Даже если рухнет мироздание вся инфраструктура, когда она оживет - брокер может поднять помещенные в него сообщения и продолжить передавать их подписчикам.
Нормально настроенный брокер позволяет существенно упростить жизнь, когда нужно маршрутизировать потоки информации между несколькими сервисами.
На неделе совершил очередной подход к нему, наткнувшись на пару занятных нюансов.
Оказалось, что настройка "не удалять очередь при рестарте RabbitMQ" вообще ниразу не значит, что надо сохранять все помещенные в нее сообщения. Удаление сообщения регулируется отдельно, при том в момент публикации можно выбрать настройку персистентентности для каждого сообщения в отдельности.
RabbitMQ позволяет принимать сообщения как синхронно, так и асинхронно. Для обоих способов предусмотрены специальные методы. Но вот беда - асинхронный прием сообщений не работает. Оказалось, сообщать RabbitMQ что я буду принимать асинхронные оповещения надо на этапе подключения к нему.
В остальном RabbitMQ прекрасен: удобно и быстро настраивается из с#, нагрузку держит.
#rabbitmq
Нормально настроенный брокер позволяет существенно упростить жизнь, когда нужно маршрутизировать потоки информации между несколькими сервисами.
На неделе совершил очередной подход к нему, наткнувшись на пару занятных нюансов.
Оказалось, что настройка "не удалять очередь при рестарте RabbitMQ" вообще ниразу не значит, что надо сохранять все помещенные в нее сообщения. Удаление сообщения регулируется отдельно, при том в момент публикации можно выбрать настройку персистентентности для каждого сообщения в отдельности.
RabbitMQ позволяет принимать сообщения как синхронно, так и асинхронно. Для обоих способов предусмотрены специальные методы. Но вот беда - асинхронный прием сообщений не работает. Оказалось, сообщать RabbitMQ что я буду принимать асинхронные оповещения надо на этапе подключения к нему.
В остальном RabbitMQ прекрасен: удобно и быстро настраивается из с#, нагрузку держит.
#rabbitmq
👍3
Наткнулся на неочевидную проблему при приеме данных от RabbitMQ. Когда блямкает оповещение, оно представляется неким классом, имеющим поле типа ReadonlyMemorySpan<byte>, то есть по большому счету ссылка на область памяти с указанием размера.
Ну я и складировал эти классы для последующей обработки. Поддал нагрузки при тестировании - и из кролика полезла какая-то фигня, которую я туда не передавал.
Сделал копирование байтиков в массив сразу по получении - и проблема рассосалась.
#rabbitmq
Ну я и складировал эти классы для последующей обработки. Поддал нагрузки при тестировании - и из кролика полезла какая-то фигня, которую я туда не передавал.
Сделал копирование байтиков в массив сразу по получении - и проблема рассосалась.
#rabbitmq
😁1
Эшу быдлокодит
На неделе надо было максимально быстро накидать незамысловатый UI для внутреннего пользования, так чтобы работало на Винде, посмотрел несколько вариантов реализации: 1. C# Win Forms 2. C# WPF. 3. C# MAUI 4. React.js У Win Forms в наличии визуальный редактор:…
У меня таки дошли руки до раскуривания реакта, ещё немного и я смогу быть junior react developer!
В несколько подходов отработал основные концепции:
1. Хранение состояний, композиция хранилищ, перерисовка компонента при изменение состояния, относящегося к ней (например - таблицы при появлении новых данных).
2. Роутинг внутри сайта: переходы между логин-экран1-экран-2 и так далее.
3. Адаптивная верстка: на мобилке - один ui, в браузере - другой.
4. Потыкал самые распространенные компоненты, типа текстового ввода.
5. Разобрался с разметкой страниц (ни капли html, что характерно).
6. Научился принимать и отправлять данные как обычными запросами, так и веб советами.
В общем, можно начинать творить:)
#react #кодинг #js
В несколько подходов отработал основные концепции:
1. Хранение состояний, композиция хранилищ, перерисовка компонента при изменение состояния, относящегося к ней (например - таблицы при появлении новых данных).
2. Роутинг внутри сайта: переходы между логин-экран1-экран-2 и так далее.
3. Адаптивная верстка: на мобилке - один ui, в браузере - другой.
4. Потыкал самые распространенные компоненты, типа текстового ввода.
5. Разобрался с разметкой страниц (ни капли html, что характерно).
6. Научился принимать и отправлять данные как обычными запросами, так и веб советами.
В общем, можно начинать творить:)
#react #кодинг #js
До недавнего времени из-за ограничений браузера для организации постоянной связи браузер-бэкенд надо было или использовать веб-сокеты и гонять через них json-ы, или использовать web-gRPC, прибавляя дополнительный узел прокси сервера на бэке, роль которого сводилась к конвертации порезанного под браузер протокола в вид, понятный человеческому gRPC.
И тут совершенно случайно узнал, что в c# совсем недавно завезли поддержку браузерной gRPC. Осталось протестировать и насадить практику использования этого чуда инженерной мысли на фронте.
И тут совершенно случайно узнал, что в c# совсем недавно завезли поддержку браузерной gRPC. Осталось протестировать и насадить практику использования этого чуда инженерной мысли на фронте.
👍1
Оказалось довольно удобно совмещать ORM с хранением jsonb в постгресе. Делаешь модельку вида:
А остальные поля, которые надо будет только читать, в т.ч. содержащие подклассы и массивы, уезжают в поле, содержащее класс (ClassField в примере). Помечяешь поле атрибутом "хранить как jsonb" и ORM сама сериализует и десериализует его. В итоге, вместо веера из десятка таблиц, разложенных по нормальным формам, получаем одну, время чтения и модификации данных соответственно уменьшается.
Итого, лёгким движением руки Postgres превращается, Postgres превращается...
в мутанта, содержащего признаки реляционки и монги.
/Напевает себе под нос/ Денормализация! Денормализация!
#postgresql
class Model
{
Int Field1,
String Field2,
String Field3,
InnerModel ClassField
}
В обычные поля таблицы кладешь то, по чему будут строиться индексы и какую-то важнейшую информацию, к которой нужен максимально быстрый доступ.А остальные поля, которые надо будет только читать, в т.ч. содержащие подклассы и массивы, уезжают в поле, содержащее класс (ClassField в примере). Помечяешь поле атрибутом "хранить как jsonb" и ORM сама сериализует и десериализует его. В итоге, вместо веера из десятка таблиц, разложенных по нормальным формам, получаем одну, время чтения и модификации данных соответственно уменьшается.
Итого, лёгким движением руки Postgres превращается, Postgres превращается...
в мутанта, содержащего признаки реляционки и монги.
/Напевает себе под нос/ Денормализация! Денормализация!
#postgresql
😁3