Как стать автором
Обновить
4
0

Пользователь

Отправить сообщение

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

Ну и конечно, шелуха проверок уровня апп пропадёт

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

О, если вы покажете такой констнейнт на БД, я бы посмотрел. Необходимость маркировки у нас задается для конкретных категорий товаров с конкретной даты. Категории товаров - это дерево, в котором есть наследование (т.е. если маркировка обязательна для промежуточного узла, то и для всех дочерних тоже). А еще обязательность маркировки зависит от страны, в которой мы торгуем.

Я не говорю что валидация не нужна. Я конкретно про констрейнты на БД.

обновления к нам прибежит клиент и спросит, а Вы же говорили что это реализовали, а оно не работает

Ну это неправда, оно уже релизнуто и может находится в этом же a\b тестиорвании месяц, и пока мы ждем этот месяц мы все равно не можем раскатать эту миграцию. Поэтому она все равно так или иначе будет раскатана руками. Да, может с доп удобствами вида now(), но это не сильно принципиально здесь уже (лично для меня из этого треда, не говорю что вообще не принципиально)

Мне гораздо интересен другая часть мессаджа, а именно зачем нам вообще нужен такой констрейнт. И я как раз доформулировал кейс. Представьте себе банальное a\b тестирование. Оно может вообще месяцами идти. И при этом у нас параллельно работают две версии. Одна - с емейлами, вторая без. Т.е. весь код должен успешно работать длительное время без этого констрейнта. Зачем мы его будем накладывать?

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

У нас почти так, только наоборот.

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

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

Проще было пожертвовать несколькими десятками секунд простоя и накатить всё одновременно. Ну и я не могу придумать кейс когда бы новое правило консистентности, выкаченное на десяток секунд раньше, ломало бы систему.

При поэтапном релизе (когда вы раскатываете новый релиз сначала на 10% инстансов например, потом на 50%, потом на 100%) несколько десятков секунд могут занимать пару часов наблюдения за раскаткой. И все это время у нас будут создаваться заказы и с емейлом и без. И все должно работать. Поэтому я не вижу большого смысла в констрейнте, который мы через несколько часов наложим.

Вам разве религия не позволяет подставлять дату динамически?

Религия доставляет мне сложность катить миграцию идеально в то же время, в которое происходит релиз кода, который запрещает так делать или обрабатывает такую ситуацию. Это если забыть про откаты релизов, например. Вплоть тдо того, что у вас может быть какой-нибудь роллинг релиз и два часа у вас половина пользователей создает заказы с емейлом, а половина без, так как у вас идет поэтапный деплой. с какого момента мне выставлять дату ограничения если там через один идут заказы с емейлом и без? такой констрейнт просто свалится, какую бы дату я не поставил (потому что все равно возможен откат релиза)

Транзакция на 2 системы с обеспечением ACID — практически не реализуемая инженерная задача.

C обеспечением ACID - да, безусловно. Но если вы пишите распределенные системы, есть вполне конкретные паттерны, например saga.

 я бы отправлял после всех БДшных чеков, и изменений БД, но до коммита транзакции в своей системе

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

Да и вообще я сторонник того что все проверки надо делать в БД,

Я лично за то, чтобы в БД были только те констрейнты, которые бизнес готов высечь на бумаге (если мы говорим в терминах DDD). Т.е. если бизнес готов сказать, что с полуночи 07.07.2021 мы заказы без емейлов дропаем, даже те, которые в 23:59 еще оформлялись в старом интерфейсе где нет емейла - то и ладно.

— прямо в коде у нас зафиксирована дата изменения схемы данных

Вот за такое делаем ментальное внушение тем, кто такое придумывает. Все изменения в DDL должны фиксироваться миграциями (если у вас конечно есть ревью изменений, тестовые контура, автотестирование и прочее). Если фиксировать дату в миграции... Задержали релиз на день - сидим хотфиксим. Релизим не ровно в полночь - сидим хотфиксим. Решили потестировать на куа базе - сидим хотфиксим.

БД гарантирует что данные консистентны и удовлетворяют CHECK'у если миграция прошла

Ваша БД - возможно. А если у вас несколько систем? А если у вас несколько внешний интеграций? Какие констрейнты вы будете отдавать им на работу с этими сущностями?

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

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

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

Если говорит конкретно про ваш кейс, то представим, что у нас простенькая доставка суши и нам всегда хватало только телефона. а вчера пришел бизнес и сказал, что хочет обязательно еще и email. Сразу возникает вопрос - становятся ли все старые заказы невалидными? наверное нет. С ними можно продолжать работать. Сразу возникают проблемы с деплоем, т.к. появляются три этапа - добавляем необязательное невалидируемое поле, потом добавляем инпуты и только потом добавляем обязательную валидацию. Но поле в БД все равно останется нуллабельным и мы не можем гарантировать остальным получателям данных по заказам, что там заполнен email

Скажем, пресловутый поиск по параметрам все равно отдается на откуп внешнему поисковому движку

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

CREATE INDEX publisherhash ON books USING HASH ((data->'publisher'));

Это понятно, что так можно, но это кажется несколько расходится с той идеей, что пользователь(оператор) может сам атрибут создать (иначе зачем нам EAV, а не предописанная в коде схема). Создавать индексы по действиям пользователя - я не уверен что хорошая затея, особенно на нагруженной базе.

Если бы у EAV не было проблем с производительностью, то все бы на нем и сидели — никто не любит накатывать DDL в продакшене :)

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

У нас на самом деле с EAV другая проблема. EAV в отличие от документного формата гораздо сложней версионировать. Вот тут проблемы (в том числе индексации) вылезают в полный рост, а минусы JSONB наоборот - уходят, т.к. больше не надо редактировать отдельное поле в документе, перезаписывая весь документ. В такие моменты удобство работы с документом вместо EAV становится прям супер очевидным/

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

del хабр чет подвисает, задублировалось

В вашем примере заведомо в проигрышной позиции JSONB т.к. для него вы выбрали GIN индекс, тогда как для EAV hash. Если я правильно понял ваш юзкейс.

Я не очень понял ваш тезис про "проигрышную позицию". Я вам процитировал документацию постгри, в которой сказано, что другие индексы для JSONB полезны только для прямого сравнения документов, а не поиска по ним. Если это неверная информация, то мне было бы интересно почитать и про это тоже. В целом меня интересуют оба подхода с самыми эффектиными индексами. Не важно, что это именно будет.

Но опять таки все зависит от исходных задач и профиля нагрузки на БД — серебренной пули не бывает.

Современный PostgreSQL имеет JSONB. Который мне кажется будет предпочтительнее к использованию на текущий момент, чем EAV.

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

Jsonb поддерживает не только GIN индексы (btree и hash также поддерживаются).

Тип jsonb также поддерживает индексы btree и hash. Они полезны, только если требуется проверять равенство JSON-документов в целом. Порядок сортировки btree для типа jsonb редко имеет большое значение, но для полноты он приводится ниже:

В вашем вопросе будет сравниваться производительность индекса с индексом без относительно кто был источником данных (EAV или JSONB — не важно).

Именно. В этом и суть вопроса. Но я на него все еще не получил ответ. Есть ли у вас бенчмарки, которые подтверждают ваши тезисы?

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

Современный PostgreSQL имеет JSONB. Который мне кажется будет предпочтительнее к использованию на текущий момент, чем EAV.

Из этих утверждений я делаю вывод, что вы считаете реализацию указанной в статье логике через JSONB производительней, чем через EAV. Я прошу вас чем-то подкрепить это утверждение и в качестве примера дал вполне конкретный юзкейс.

Я знаю, поэтому я и указал в скобках GIN. мой вопрос не про возможность, а про производительность.

А есть сравнение производительности поиска по json (через GIN) и поиска в EAV (где, полагаю, достаточно какого-нибудь хеша)? Ну т.е. например задача, найти все сущности у которых не заполнен (отсутствует значение) атрибут X.

Не уверен что найду сходу исходники, статью можно найти здесь
Помимо нейросеток я бы предложил и более «дубовые» подходы, но идея все та же — зная положение мяча на N предыдущих кадрах, можно не пытаться искать его на всем изображении, а искать его в достаточно «ограниченном подходе. Можно почитать на эту тему например вот en.wikipedia.org/wiki/Particle_filter

С учетом того, что у вас в примере очень хорошо отслеживается большая часть положений это поможет избежать откровенных выбросов, которые проскакивают в промежутке.

З.Ы Делал диплом, только трекал не мяч, а спортсменов

en.wikipedia.org/wiki/Java_Classloader
Во всяких сях тоже есть
en.wikipedia.org/wiki/Dynamic_loading#In_C/C++
ну и пхп, да. может еще где-то есть, не знаю
На самом деле, интерес в том, что если у вас кухня производит борщи 24\7 — то оно так и случится. Просто обывательская кухня этим не занимается в таком режиме, там больше фишек и появляются доп. абстракции, что ложка для борща не просто существует и хранится, а берется из репозитория ложек, который имплементирован в виде ящика на кухне.
Потому что делать просто DDD в вакууме — сложно. Неплохо его соединять с другими техниками, навроде слоистой архитектуры. и тогда этот Shared (который безусловно нужен) просто отъезжает в правильный слой вместо доменного кода

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность