Комментарии 210
Обсуждалось 4 года назад
«В карантин нагрузка выросла в 5 раз, но мы были готовы». Как Lingualeo переехал на PostgreSQL с 23 млн юзеров https://habr.com/p/515530/
SQL — это язык для агрегации данных, а не язык для описания бизнес-логики приложения
Дальше читать не имеет смысла
https://en.wikipedia.org/wiki/SQL
"The scope of SQL includes data query, data manipulation, data definition, and data access control."
Это точно.
Насчёт тестирования. Автор наверное забыл упомянуть про возможность тестов на реальной СУБД? Я не то, чтобы фанат хранимок, но надо как-то реальные недостатки обсуждать, а не проблемы возникающие от незнания/неумения.
Проблемы, описанные в разделах "Сложность в тестировании" и "Автоматическое тестирование или unit-тесты" в значительно мере могут решены связкой test-containers + [ваш любимый инструмент миграции] (для распространённых СУБД всю конструкцию можно запустить за день с нуля). В этом случае, интеграционный тест на хранимку собственно и будет её актуальной документацией.
Автор наверное забыл упомянуть про возможность тестов на реальной СУБД?
Это интеграционные тесты, а он говорит про юнит-тесты.
могут быть решены связкой test-containers + [ваш любимый инструмент миграции]
Он же не сказал, что они не могут быть решены, он говорит, что это сложнее. В этом я с ним согласен.
Хм, а в чем проблема в unit-тестах для хранимых процедур?
Открываем транзакцию, заполняем фикстурой (тривиальный insert из таблицы с тестовыми данными), вызываем процедуру, проверяем утверждения, откатываем транзакцию.
Это довольно просто пишется, быстро работает, легко модифицируется.
В том, что это не юнит-тест. Это интеграционный тест с вводом-выводом по сети и на диск. Юнит-тест в классическом понимании так не делает.
С транзакцией тоже есть вопросы. Вот допустим у меня есть бизнес-требования "Сохранить объект в базу с одним статусом, отправить по сети в другую систему, при успешной отправке ставить другой статус, при ошибке ставить третий". Здесь должно быть 2 транзакции, до и после отправки по сети. Как написать тест на эту логику? В приложении я могу замокать базу и клиент к другой системе, и проверить, какие данные будут через них отправляться, без фактической отправки.
Да, дальше появляются советы сделать таблицу-очередь, читать из нее в приложении, отправлять и обновлять статус из приложения, потом другой программист не может найти, где реализована эта часть бизнес-требований. Это как раз к вопросу "собирать информацию по крупицам".
Во-первых, откуда в указанном примере сеть и диск? Сам тест пишется на sql, выполняется внутри БД и на диск ничего не пишет.
Во-вторых, что за "классическое понимание"? Единица тестирования - хранимая процедура, ее и тестируем, в чем проблема?
В-третьих, то, что описано как "бизнес-требование" - таковым не является, описана техническая реализация. Нужно ли именно такое - не понятно, тем более в системе уровня "логика в БД".
Ну и так далее....
Во-первых, откуда в указанном примере сеть и диск?
А таблица с тестовыми данными у вас в магическом эфире хранится? Всякие журналы запросов тоже наверно на диск пишутся.
Насчет сети не знаю, программа, которая запускает тест в БД, наверно как-то к ней подключается?
Во-вторых, что за "классическое понимание"?
https://en.wikipedia.org/wiki/Unit_testing
Unit testing, a.k.a. component or module testing, is a form of software testing by which isolated source code is tested to validate expected behavior.
One goal of unit testing is to isolate each part of the program and show that the individual parts are correct. A unit test provides a strict, written contract that the piece of code must satisfy.
https://www.baeldung.com/cs/unit-testing-vs-tdd
Isolated. A unit test shouldn’t modify or depend on any external state.
В-третьих, то, что описано как "бизнес-требование" - таковым не является
Именно является. Аналитики от бизнеса знают, что такое БД и сохранение данных. И хотят сначала сохранить в нашу базу, а потом отправлять в другую систему. Иначе может быть так, что в другой системе запись создалась, а в нашей после этого произошла ошибка транзакции, и данные не сохранились. Это именно бизнес-логика, такая же как "После создания заказа отправить email пользователю".
[о да, религиозные фанатики в интернете...]
В сторону от темы: Вы же понимаете, что все эти требования, про то, что юнит-тест должен, а чего не должен, не обоснованы ничем (я, естественно, читал все эти теоретические обоснования, и говорю это на основе прочитанного), кто-то верит, что оно должно быть так, как в википедии написано, кто-то нет. Это не особо важно - разработка это ремесло, а не теория. Есть распространённые примеры других подходов, например в Рельсах тесты на реальной БД идут из коробки, и называются юнит-тестами (работает в точности по описанной выше схеме).
По теме: Мы говорим не об абстрактном коде, а именно о коде взаимодействующем с базой данных. Этот код почти всегда включает запросы к БД (ORM тоже, просто вы их не видите). Т.е. у нас есть, как-бы isolated source code, который включает инструкции к внешней системе, которые только эта внешняя система и может интерпретировать. Это точно isolated? Печальный факт состоит в том, что на моках базы данных вы никак не проверите, что внутри этих запросов написано (нестрого говоря, тесты репозитория на моках - это погружение в мир иллюзий, у вас как-бы 100% покрытие, но при этом всё равно deploy-and-pray стиль интеграции). И если раньше (давно) тестирования кода на реальной базе данных было сопряжено с некоторыми техническим трудностями, то сейчас контейнеризация решила большую часть этих проблем. Технически, у вас всё равно есть какой-то setup метод, который выполняется до тестов, и большая ли разница, общие моки там настраиваются, или контейнер в память поднимается.
Тут, конечно, может быть терминологический вопрос, он же вопрос про скоуп интеграционного теста. В нашей практике, интеграционный тест - это тест который который поднимет все микросервисы, участвующие в каком-то воркфлоу. Юнит-тест, понятно, изолированный кусок кода на моках. Но между этими вариантами есть целый спектр других уровней автоматизированных тестов, и где там ставить границу интеграционного теста это, по большому счёту, вопрос соглашения.
И по основному тезису - если у вас есть тесты на реальной БД (называйте их как угодно), то тестирование хранимок ничем не отличается от тестирования запросов. Если таких тестов у вас нет... ну, не знаю, наверное есть отрасли где данные ничего не стоят, сам не видел, врать не буду.
Вы же понимаете, что все эти требования, про то, что юнит-тест должен, а чего не должен, не обоснованы ничем
Был вопрос "Что за классическое понимание?", я привел ответ с пруфами. Неважно, чем они обоснованы, это все равно является ответом на этот вопрос.
Т.е. у нас есть, как-бы isolated source code, который включает инструкции к внешней системе, которые только эта внешняя система и может интерпретировать. Это точно isolated?
Source code сам по себе не является isolated, он явлется isolated только в тестах. Тесты настраиваются таким образом, чтобы сделать код юнита isolated. Это написано в приведенном тексте: "goal of unit testing is to isolate".
Печальный факт состоит в том, что на моках базы данных вы никак не проверите, что внутри этих запросов написано
Вот разговор как раз о том, что для теста юнита это совершенно неважно. В юнит-тесте мы проверяем только поведение самого юнита на заданных данных, а не всех его нижележащих компонентов. На эти компоненты есть свои юнит-тесты.
Ну, таблица для тестов может и в памяти жить, в чем проблема? Если для тестирования используются искусственные данные (а в юнит-тестах обычно так и есть), то все данные будут в памяти и так. Транзакция до завершения может и пишет в журнал, но его тоже можно развернуть в памяти, делов-то.
Все это достаточно просто решаемые вопросы, причем решать их умели еще лет 20 назад.
И нет, если у вас бизнес (не аналитики, а именно бизнес) знает про БД, то тут какие-то проблемы. Впрочем, в указанном примере вообще нет (и не может быть) решения, только eventually consistency, саги и так далее. Где и как будет реализована сага - бизнесу вообще без разницы (
Ну, таблица для тестов может и в памяти жить, в чем проблема?
Ну а как тестовые данные туда попадают? Какая-то программа подключается по сети, читает их откуда-то с диска и добавляет.
Все это достаточно просто решаемые вопросы
Ну а с юнит-тестами в приложении их вообще решать не надо. Это и показывает, что такие тесты в базе отличаются от юнит-тестов в приложении.
Смысл вообще не в том, что данные должны быть в памяти, а в том, чтобы тест не взаимодействовал с внешним для него состоянием или системами.
И нет, если у вас бизнес знает про БД, то тут какие-то проблемы.
Не вам указывать бизнесу, что ему можно знать, а что нет. Есть требование убрать фантомные записи в сторонней системе, изложенное с помощью аналитика формальным языком в задаче программисту.
Где и как будет реализована сага - бизнесу вообще без разницы
Я не сказал, что бизнесу есть разница, где и как реализована сага. У бизнеса есть требование "Сначала сохранить в нашей базе с этим статусом, потом отправлять в другую систему, по результату отправки обновлять статус". Тут нет требований где и как это реализовывать.
только eventually consistency, саги и так далее
Мне кажется, что в этом примере, сага будет некоторым перебором. Здесь, как мне кажется, вполне хватит обычного transactional outbox, если мы можем гарантировать идемпотентность по сообщениями на стороне системы получателя.
Совершенно правильные замечания с точки зрения казуального юзера, взаимодействующего только с верхними слоями БД. Конечно в отношении "сервис - база данных" не должны участвовать хранимки.
Однако не стоит забывать, что то, что вы видите от БД это лишь верхушка айсберга. Как известно на поверхности находится лишь 1/10 часть.
Само формирование базы не представимо и полностью невозможно без использования хранимок.
Если переводить в метафору - вы, в данном случае, владелец кредитного китайце в пробке, рассуждающий о том, что механическая коробка передач более не нужна и вообще морально устарела. А теперь представьте лицо профессионального гонщика (или Вин Дизеля), который бы это услышал. И вас понять можно, но и глупость, которую вы морозите, сложно оправдать. Не стоит обобщать весь мир АйТи под ваш опыт. *Смайлик клоуна*
мне, как .net разработчику, перешедшему в команду с достаточно большим количеством данных, прекрасно понятны мотивы, побудившие автара на написание сего опуса. Было бы все так просто, работоли бы все на одном "самом лучшем языке программирования". Если в приложении есть нормальный бэкэнд, очевидно - не стоит размазывать логику между ним и БД. Но в реальной жизни, не все ПО строится по трехзвенной архитектуре - есть целый пласт задач, где BLL на уровне СУБД суть рациональное решение.
Любой инструмент должен быть применен по назначению. В том числе и хранимые процедуры.
Текст процедур вообще ничем не отличается от текста на, к примеру, Java. Его можно прекрасно положить в GIT и так же версионировать. И точно так же документировать, точно так же тестировать на тестовой бд.
Единственный значимый аргумент - это привязка к конкретной СУБД. И то каждый сам для себя определяет допустимую степень риска. Кому было нужно - потратили время и деньги и перешли с oracle/mssql. Значит, задача не является нерешаемой.
Паническое нежелание работать с ХП иногда приводит к маразму. Настолько разработчики боятся малейшей логики в бд, что вместо select max(...), загружают список записей на клиента и уже там находят максимальное значение нужного поля (сам видел)
Настолько разработчики боятся малейшей логики в бд
Я видеть такой кейс(регулярно повторяемый)- backend выгружает весь набор строк и фильтрует на стороне приложения.
Закономерный итог -"а почему в psql запрос отработал миллисекунды а форма открывается минуту ?"
Ну все ж адекватно составленный SQL запрос (с max() вместо выгрузки всего и вся) - это не про хранение логики в БД.
Адекватно составленные оптимальные и быстрые SQL-ники тоже в коде проекта хранятся, просто в БД выполняются :)
Ключевое слово адекватный.
По ходу проведения импортозамещения с адекватными и профессиональными разработчиками большие проблемы .
Повторяюсь, сорри, но для них СУБД это хранилка данных. Как работает СУБД они не знают и знать не хотят .
В результате - "у нас проблемы с СУБД , очень много ожиданий Client read" , или "вы зачем используете эксклюзивные блокировки ? Это не мы у нас фреймворк такой" и т.д. и т.п. Ну а про то , какие запросы генерят ORM это отдельная тема . Я лично видел план запроса стоимостью триллион (10^12) и вопрос руководителя разрабов - "почему у нас медленно открывается форма "
Раньше было даже смешно и прикольно . Но когда происходит срыв сроков и постоянные аварии уже не смешно - "У нас проблемы с импортозамещением."
А с хранимками ситуация очень простая - современные разработчики просто не умеют писать бизнес логику в СУБД. Все наработки предыдущих поколений спустили в трубу в угоду моде и трендам.
На одном проекте, разработчики backend - в очереди стояли , набор вообще без проблем , на любой вкус и цвет. Разработчика СУБД искали год . Нашли с большим трудом.
Вот и приходится писать бизнес логику , ролевую модель , ограничения целостности и корректности данных , фильтрацию и агрегацию в приложении, а не в СУБД и придумывать оправдания типа "хранимки это рудимент".
Все просто .
современные разработчики просто не умеют писать бизнес логику в СУБД
Это наследие атлантов, великих колдунов древности. Смертные не могут в это чернокнижие....
для них СУБД это хранилка данных. Как работает СУБД они не знают и знать не хотят
современные разработчики просто не умеют писать бизнес логику в СУБД
набор вообще без проблем
Наверно есть какая-то причина? Раз много разработчиков выбирают backend, а не СУБД, то наверно backend им почему-то больше нравится?
Может надо спросить этих самых разработчиков, почему им не нравится разработка в СУБД?
Но нет, некоторые люди не хотят поверить, что так и есть. Не понимают, что на один их проект с постоянными авариями есть тысячи, которые с логикой в приложении работают нормально, а аварии если и происходят, то не создают больших проблем и решаются в рабочем порядке. Вот и приходится придумывать оправдания типа "в угоду моде и трендам".
Ну а про то , какие запросы генерят ORM это отдельная тема
Ну, холивар по поводу ORM это тема отдельной статьи и отдельного треда с комментами.
То, что в экосистемах бэкендовых ЯП присутствуют такие чудища как ORM - это не значит, что надо от бэкенда отказываться и переносить все в БД. Можно же отказаться от ORM, верно?) Ну или на худой конец поменять саму ORM на более вменяемую
Можно же отказаться от ORM, верно?) Ну или на худой конец поменять саму ORM на более вменяемую
В современных условиях это невозможно . Повторюсь - современное поколение разработчиков просто не умеет писать запросы и разрабатывать архитектуру СУБД без ORM и библиотек .
Я помню как они удивлялись - "а какая библиотека была использована для реализации графа и обхода дерева ? Да никакая , взял и написал алгоритмы , вспомнил 2й курс КАИ и теорию графов". Для них был шок, что можно самому что то сделать.
Может быть это мне не везёт. С разрабами , но 4й год одно и тоже - ORM + "у нас фреймворк такой". и всегда - как только пошла промышленная нагрузка -"мы уперлись в СУБД , дайте нам волшебную комбинацию конфигурационных параметров ".
Я же не просто так занялся темой производительности СУБД - теперь я могу доказать средствами объективного контроля - "с СУБД аномалий нет идите разбирайтесь со своим приложением".
Настолько разработчики боятся малейшей логики в бд, что вместо select max(...), загружают список записей на клиента и уже там находят максимальное значение нужного поля
Будь так, слали бы запрос с select max(...)
и ХП не понадобилась бы. А тут больше похоже на то, что банально не подружились с генератором запросов в ORM.
Задача была именно такая: найти запись по сотруднику с максимальным score
Решение изумило: скачивали на клиента при каждом запросе (нагрузка была примерно 200 tps) около 20 строк, руками пробегали этот список и находили строку с максимальным значением, и брали все атрибуты именно с неё.
Это аргумент ни за, ни против хранимок. Чтобы отправить в базу max(..) хранимки не нужны. Да это и современные орм умеют делать полностью прозрачно. Некоторые даже могут обновлять данные не выбирая их на клиента, там где сценарий позволяет.
Бизнес-логика в базе это однозначно плохо. Банально затрудняет отладку и читаемость кода. Но иногда это вполне приемлемая цена за производительность. От задачи зависит.
Вытаскивать N записей из базы чтобы найти среди них одну по банальному условию это профнепригодность разработчика. Если эти N записей не используются потом где-то еще, конечно. Таких абсурдных косяков можно наделать где угодно, не только при работе с базой. Если разработчик шлепает код на отвали, он найдет где накосячить.
Бизнес-логика в базе это однозначно плохо. Банально затрудняет отладку и читаемость кода.
Данное утверждение будет верно только при одном важном уточнении - читатель и отладчик не обладает знаниями Database Development .
Что и подтверждается следующим утверждением
Если разработчик шлепает код на отвали, он найдет где накосячить.
Данное утверждение будет верно всегда. Читать код, который собран в одном проекте все равно проще, чем переключаться из проекта в проект. То же самое и с отладкой. Даже если читатель и отладчик обладает божественными знаниями во всех возможных сферах, это утвреждение неверным не становится. Что чем у вас подтверждается - решительно непонятно. А главное зачем.
руками пробегали этот список и находили строку с максимальным значением, и брали все атрибуты именно с неё
Если кроме самого значения нужны остальные атрибуты строки, то как вы это решите через select max()?
Типа такого:
Select *
From example_table t1
Where t1.empl = 123
And t1.score = (select max(score) from example_table t2 where t2.empl = 123)
Order by id desc
Limit 1
Пишу с телефона, уж простите, не форматирую текст
Так это ж не один селект, а два с подзапросом и копипастой условий в WHERE. Это далеко не "вместо [простого] select max()". Вполне логично, что разработчикам эта портянка показалась сложнее условного
employeeEntity.exampleEntityList.sort((a, b) => b.score - a.score).first()
Другое дело, что это можно решить и запросом, только без select max().
SELECT * FROM example_table WHERE empl = 123 ORDER BY score DESC, id DESC LIMIT 1
ExampleEntity.find().where('empl', '=', 123).orderByDesc('score', id').limit(1).one()
Можно и так. В любом случае, запрос будет быстрее и нагляднее, чем грузить рекордсет на клиента. Даже странно, что приходится объяснять очевидное
Вот именно что вариант с загрузкой рекордсета короче и нагляднее. Во-первых, по количеству символов. Во-вторых, в приложении есть либо автоподгрузка exampleEntityList при первом обращении без репозитория, либо уже существующий метод репозитория ExampleEntityRepository::findAllByEmpoyee(Employee employeeEntity)
. А с запросом "ORDER BY score DESC" надо делать в репозитории новый метод.
SELECT DISTINCT ON (t1.empl) *
FROM example_table t1
WHERE t1.empl = 123
ORDER BY t1.empl, t1.score;
О DISTINCT ON не слышали?
В нашем MySQL нет такой конструкции. В ненашем MS SQL, говорят, тоже нет.
"select max()", насколько я понимаю, в таком запросе тоже не будет.
В нашем MySQL нет такой конструкции.
Переходите на PostgreSQL. MySQL даже INSERT/DELETE/UPDATE ... RETURNING не поддерживает в CTE, что сильно ограничивает область его применения при сложных SQL запросах.
"select max()", насколько я понимаю, в таком запросе тоже не будет.
Я написал пример выше. Максимальное значение score для указанного empl запрос выводит. Вместе с остальными полями из этой записи. Если WHERE вообще убрать, то выведет максимальное значение score для каждого empl. И тоже со всеми остальными полями из этой записи.
Я написал пример выше.
Не знаю, зачем вы показываете мне пример без select max(), когда мой вопрос был про select max(). Как сделать без select max() я и сам знаю.
мой вопрос был про select max()
Не вижу.
Вижу:
найти запись по сотруднику с максимальным score
Никаких ограничений на использование SQL конструкций в этой постановке нет. При этом DISTINCT ON в подобных задачах явно выигрывает.
Вот Вы зачем то приплели к этой задаче max()
Если кроме самого значения нужны остальные атрибуты строки, то как вы это решите через select max()?
На что я резонно ответил, что если "кроме самого значения нужны остальные атрибуты строки", то нужна не агрегатная функция, а DISTINCT ON, именно для этого и предназначенный.
Не вижу.
Ctrl+F "select max", первый результат.
Если вступаете в дискуссию, то неплохо бы сначала ознакомиться с контекстом.
На что я резонно ответил, что нужна не агрегатная функция
А я вам резонно ответил, что я и сам это знаю, а разговор был про select max, именно поэтому я и задал вопрос.
Ctrl+F "select max", первый результат.
Там не было требования, как в измененной Вами постановке, что "кроме самого значения нужны остальные атрибуты строки"
Вы вообще понимаете разницу, между поиском максимального значение нужного поля и поиском кортежа, содержащего максимальное значение нужного поля? Это разные задачи и они требуют разные конструкции SQL.
как в измененной Вами постановке
Это не измененная мной постановка. Первый раз фраза про атрибуты встречается не в моем комментарии. Ctrl+F "брали все атрибуты именно с неё"
Вы вообще понимаете разницу
Я понимаю разницу, именно поэтому и написал вопрос. Это вы не понимаете, что вам говорят. Читайте внимательно дискуссию, прежде чем спорить.
Настолько разработчики боятся малейшей логики в бд, что вместо select max(...), загружают список записей на клиента
Ну это конечно неправильно в определенных ситуациях, но в других ситуациях это может быть более подходящим решением. Без контекста нельзя точно сказать. Кроме неумения использовать ORM, как сказали выше, могут быть например такие причины:
- Список записей потом используется для чего-то еще.
- Для произвольного запроса надо писать 20 строк, а для вычисления в приложении 1. Тот, кто советует отправлять max() в базу, поддерживать их конечно не собирается. При этом записей в этой выборке не больше 10.
- В коде проще отслеживать и менять логику средствами IDE, чем в строковых константах с SQL. Если разработчик приложения пропустит это место при изменениях требований, вы (DBA) будете ответственный или он? Вы будете исправлять этот баг в строковой константе? Зато 10 микросекунд сэкономили.
У нас архитектор вообще запрещает хранимки, триггеры и прочую логику в БД
Текст процедур вообще ничем не отличается от текста на, к примеру, Java.
Ну нет.
Во-первых, выразительность современных бекенд-языков (того же Java) на порядки лучше, чем у процедурных расширений SQL, используемых в современных СУБД. Попробуйте для сравнения написать более-менее крупную систему на Java и на PL/pgSQL, потом нам расскажите, что разницы никакой нет.
Во-вторых, инструментарий тоже очень разный. Например, для бекенда есть целая пачка крутых IDE, для СУБД я как не искал, не нашёл ничего похожего (чтобы и работа с Git, и тесты гонять, и отладка нормальная и т.д.). А ведь разработка не только в IDE упирается, и с экосистемой в СУБД всё значительно хуже.
За большей частью текста полностью за !!! Работал 5 лет назад с оракловской бд, это дикая боль. За исключением как у них реализован рекурсивный обход, все остальное, жесть. Бизнес логика написана хранимками, и упиханна в пакеджи. Которые нужно ещё компилировать . Собирается все херово . Инстансы ещё нужно определенной версии. Но самая жопа это логика в базе!!!! База должна уметь репликации, дампить нормально, а не валится или битые с ходу делать. Я не хочу разбираться в сиквенсах, мне нужно надёжно данные сохранить . Уметь в кластер и давать АДЕКВАТНЫЕ ответы на ошибки. А не засирать диск тупыми логами , с нулевой информативностью . (Может в настройках дело, но это говно даже перезапустить боялись ) потому что она поднималась раза с 5 го. Логика - в код, данные в бд
При каждой пересборке пакетов, отлетают клиенты. И есть шанс уронить вообще все.
Согласен с автором логика в бд - за такое четвертовать !
Прочитав статью можно подумать, что хранимые процедуры были придуманы какими-то идиотами, у которых просто нормального ORM-а не было. И что у хранимок нет никаких плюсов, а сугубо одни минусы. А между тем плюсы всё-таки есть.
Хранимые процедуры заранее компилируются и оптимизируются движком SQL. И поэтому теоретически работают быстрее, чем просто запросы к базе, делающие ту же работу, что и процедуры. Хотя этот плюс несколько нивелирован современными движками БД, которые кэшируют SQL запросы и их результаты, в том числе параметризуемые запросы.
Лучший контроль за транзакциями и исключениями на низком уровне.
Тонкие оптимизации, недоступные когда вы обращаетесь к БД через различные высокоуровневые прослойки, имеющие те или иные ограничения.
Хотя я лично и сам ненавижу, когда логика размазана по слоям, и что там не очень то ООП получается на уровне БД когда программируешь. Но не упоминать, что у процедур есть и плюсы - это странно.
Как вы так оптом, легко и просто, умножаете на ноль целую технологию.
У любой технологии есть свои «+» и «-», и для разных задач используют разные методики.
Способ хранения данных, доступ к ним определяется на этапе проектирования системы. Даже типы серверов (MS SQL, Oracle, MySQL, ..) отличаются по функционалу, и все это нужно учитывать.
Мне кажется, Ваше отношение к данной технологии вызвано неграмотно спроектированной системой на этапе бизнес логики, вызывающей такие проблемы. Должен быть уровень данных, предоставляющий данные в верхний уровень, и программист, пишущий, к примеру, на .NET, может совсем не знать что там внутри- SQL, XML или что-то совсем другое.
Тут, как в анекдоте:
-Вы не любите кошек? Да вы просто не умеете их готовить!
и программист, пишущий, к примеру, на .NET, может совсем не знать что там внутри- SQL, XML или что-то совсем другое.
Одни говорят, что автор не знает и не разобрался, другие, что он и знать не должен)
Кто будет писать в приложении этот "уровень данных, предоставляющий данные в верхний уровень" и потом поддерживать, вы (DBA) или разработчик приложения? Зачем ему эти сложности?
Хранимые процедуры замечательно тестируются, отлично оптимизируются. В задачах, для которых они предназначены, нет ни одного ЯВУ, который был бы более выразителен. Добавляют ещё один уровень безопасности, полностью скрывая реальные структуры данных, полиморфны, можно легко добавить трейсинг, профайлинг и т.п., прекрасно мигрируют на другую СУБД даже без ребилда и деплоя приложений, можно без труда реализовать поддержку множества СУБД, классно помогают в скейлинге/миграции схемы когда нужно осуществить плавную трансформацию в фоне петабайтов данных и временно спрятать её за вызовом хранимки. У нас замечательно и из Linq генерируются хранимки. А вот за что точно надо отрывать руки - это когда противники хранимок гоняют гигабайты данных туда-сюда, пропуская их через лес уродливого кода, для работы в таком ключе вообще не приспособленного))
за что точно надо отрывать руки - это когда противники хранимок гоняют гигабайты данных туда-сюда, пропуская их через лес уродливого кода, для работы в таком ключе вообще не приспособленного
"В детстве , я таких убивал. Из рогатки".(с)
Хотел написать всё тоже самое с примерами с предыдущих мест работы. Но нашёл ваш комментарий, с которым полностью согласен, и меня отпустило. Похоже, автор статьи просто не умеет готовить крокодилов. Хочу только напомнить ему, что каждый инструмент имеет свои границы применимости, и каждый специалист применяет их в меру своей квалификации.
У нас замечательно и из Linq генерируются хранимки.
Генерируется код хранимок или хранимки из linq вызываются?
А вот за что точно надо отрывать руки - это когда противники хранимок гоняют гигабайты данных туда-сюда, пропуская их через лес уродливого кода, для работы в таком ключе вообще не приспособленного))
Как уже отмечали, это не относится к теме использования или не использования хранимок.
Генерируется код хранимок или хранимки из linq вызываются?
Генерируется код хранимок, добавляя по пути всевозможные обвязки (валидация, авторизация, профайлинг, трейсинг и прочие "separated concerns" в зависимости от ситуации).
Как уже отмечали, это не относится к теме использования или не использования хранимок.
Ссылка на комментарий, где вся аналитика сводится к функции max(...)? Это шутка? Замените max(…) на max(…) OVER (PARTITION BY ...), посмотрите как в наиболее популярных ORM это будет выглядеть и ваша карета превращается в тыкву, поскольку вы либо мешаете SQL с кодом ORM, получая уродство. Либо тащите весь рекордстет, чтобы его партиционировать руками и вернуть на порядки меньше строчек. Уродство плюс сильный оверхед по ресурсам. Я уж не говорю, как это любят СУБД-блокировочники. Это и есть то, о чём я говорил.
Аргумент в том треде - антипаттерн по своей природе. Какие-то "современные ORM" имеют какие-то "дополнительные функции". Какие ORM? Какие функции? Почему ORM должны иметь эти функции? ORM - это маппинг по определению. Точка. Как только кто-то начинает на него возлагать больше функций нужно сразу задаться вопросом, а где предел? Вы хотите в каждую ORM на каждом языке программирования втащить пародию на SQL?
Генерируется код хранимок
Тогда это как раз получается orm, который умеет компилироваться в хранимки. Если не секрет, что за продукт?
Ссылка на комментарий, где вся аналитика сводится к функции max(...)? Это шутка? Замените max(…) на max(…) OVER (PARTITION BY ...), посмотрите как в наиболее популярных ORM это будет выглядеть
Там не было ни слова про orm, никто не мешает использовать в приложении raw sql.
Тогда это как раз получается orm, который умеет компилироваться в хранимки. Если не секрет, что за продукт?
ORM работает только когда маппит объекты в параметры хранимки и возвращённые ими рекордсеты обратно в объекты. Билд-тайм генерация хранимок со всеми теми обвзяками, которые я озвучил и деплойментом никаким боком к ORM не относится. Продукт внутренний.
Там не было ни слова про orm, никто не мешает использовать в приложении raw sql.
Прочитайте первый же абзац по своей же аргументационной ссылке. Он там на 2/3 посвящён ORM.
Что мне делать с агрументом "никто не мешает"? Если вы работаете в команде и у вас есть нормальные DBA/DBD, то они вам помешают. Поскольку у них нет ни малейшего желания продираться через заросли бэкенд-кода. Если вы работаете в одиночку, то никто не мешает затащить в код, скажем, HTML, CSS, JS заодно. И в целом использовать любые, самые худшие практики.
ORM работает только когда маппит объекты в параметры хранимки и возвращённые ими рекордсеты обратно в объекты. Билд-тайм генерация хранимок со всеми теми обвзяками, которые я озвучил и деплойментом никаким боком к ORM не относится.
ну да, а миграции и генерация sql куда из orm делись? и какая разница, когда код для базы генерируется во время компиляции или во время исполнения. от этого функциональностью orm это быть не перестает.
Продукт внутренний
то есть качество того, что он генерирует не оценить. придется верить на слово.
Прочитайте первый же абзац по своей же аргументационной ссылке
мы видимо разные абзацы читаем. смысл цитаты в том, что можно как из приложения использовать всю мощь sql, так и в каком-нибудь процедурном расширении бд по циклам бегать.
ну да, а миграции и генерация sql куда из orm делись? и какая разница, когда код для базы генерируется во время компиляции или во время исполнения. от этого функциональностью orm это быть не перестает.
Вы такой смысл вкладываете в определение Object Relational Mapper (ORM)? Беру вашу "функциональность orm", ищу в Википедии, на четырёх знакомых мне языках... не нахожу. В самом популярном ORM для .NET (Dapper)? Нет! Беру второй по пополуряности - EF, у них эта функциональность есть, но они открещиваются. Говорят что "data access technology" и мооооогут использоваться как ORM, даже перечисляя что они под этим подразумевают. Без труда могу ещё немало примеров примеров привести. Я даже в Google Scholar заглянул, думал может там какое веяние. Так где мне найти это новое определение ORM, чтобы какой-то смысл в нашем разговоре вообще был?
то есть качество того, что он генерирует не оценить. придется верить на слово.
С верой в генерацию LINQ-to-SQL - к Microsoft. Откройте для себя метод ToQueryString. Можете у них провести и ревью Blazor. Его мы сейчас ещё активней используем для генерации SQL. А всевозможные обвязки мы пишем также как и вы свой "никто не мешает использовать в приложении raw sql", в качество которого мне остаётся только верить.
мы видимо разные абзацы читаем
Вы не можете по своей ссылке в первом абзаце найти слово "орм" во фразе:
Да это и современные орм умеют делать полностью прозрачно. Некоторые даже могут обновлять данные не выбирая их на клиента, там где сценарий позволяет.
Спасибо за дискуссию, но на этом её стоит завершить.
Следующим шагом объявим рудиментом еще и функции. Ведь их отличия от процедур минимальны. Ну а напоследок можно и SQL объявить рудиментом, так как NoSQL СУБД имеют ряд преимуществ.
Или все же "кесарю кесарево"? Может "золотого молотка" не бывает и любой инструмент имеет свою область применения?
Но даже при таком подходе обычные crud операции можно реализовать как ХП, и вызывать их
Можно. Только нафига?
Это будет гарантировано быстрее
Насколько быстрее? Через сколько часов работы приложения окупится дополнительный час работы программиста?
Откуда предположение, что логика в приложении обязательно означает падение системы? В Гугле тоже важна надежность, и падение тоже стоит дорого, но я сомневаюсь, что там логика на хранимых процедурах. И даже если считать, что для таких систем использование хранимых процедур оправдано, то их не так много, а для остальных утверждения в статье будут верными.
за пару минут наверное
Откуда такая оценка? Если час работы senior-программиста допустим 2000 р, то экономия за минуту работы сервера получается 1000 р. Если это 30%, то работа сервера стоит 3000 р в минуту или 130 млн рублей в месяц. Как-то многовато для сервера.
Откуда предположение, что логика в приложении обязательно означает падение системы?
Падения системы обязательно будут в любом случае. Это жизнь. Но вероятность их возникновения при наличии транзакций, объединяющих множество запросов к БД, намного выше, когда логика в приложении, а не в СУБД. Просто потому, что сервис приложения может упасть, зависнуть, потерять связь с БД. И транзакция будет удерживать блокировки вплоть до истечения таймаута и закрытия соединения с приложением со стороны СУБД. А за это время может такая очередь выстроится, что запросы уже начнут отстреливаться по таймаутам или дидлокам.
Ошибкой в хранимой процедуре уложить СУБД - надо очень постараться. А ошибкой в коде сервиса уложить или зациклить этот сервис - легко и просто. У меня, судя по Grafana, таких проблем около десятка ежедневно. Все же система активно развивается и ошибок не избежать. Но рестарт контейнера одного инстанца одного сервиса - это мелочи, по сравнению с остановкой всех инстанцов сотен сервисов, работающих с одной СУБД.
Полностью согласен.
Наконец-то адекватный комментарий от человека с хайлоад нагрузкой и про финансовые данные.
Отсутствие хранимок при crud операциях это точно не про хайлоад Энтерпрайз.
Автор просто не сталкивался с грамотным их использованием, где и масштабирование в кубере сервисов с логикой обеспечивается и горизонтальное масштабирование стейтфул адаптеров к бд.
Только нафига?
Например, с завидной регулярностью вижу от ORM такие запросы, которые по производительности уступают оптимизированному коду на plpgsql даже не на порядок, а на два-три. Можно, конечно, отложив в сторону ORM, предложить .NET разработчику включить в свой код целый ворох кода на plpgsql. Но тогда не только этот разработчик, но и любой поддерживающий этот код, должен очень хорошо знать не только C#, но и plpgsql. А можно этому разработчику предоставить представления, функции или процедуры, написанные другим разработчиком, специализирующимся на plpgsql.
Теоретически, когда то в будущем, может и появятся ORM умеющие использовать в CTE INSERT/UPDATE/DELETE RETURNING, применять pg_variables или переменные-массивы композитного типа вместо временных таблиц, понимать когда CTE надо явно материализовать, когда принудительно JOIN надо пребразовать в JOIN LATERAL или подзапрос и т.п. Но пока таких ORM даже не горизонте не видно.
Через сколько часов работы приложения окупится дополнительный час работы программиста?
Бывает, что в первые же минуты использования. Например, кто первый ответит на заявку, оперативно и достаточно точно спрогнозировав её доходность и сроки исполнения, тот, с большой вероятностью, и станет подрядчиком. А доходность заявки может составлять десятки тысяч рублей.
вижу от ORM такие запросы, которые по производительности уступают оптимизированному коду на plpgsql даже не на порядок, а на два-три
Это не отвечает на заданный вопрос. Вы неявно предполагаете, что увеличить сложность поддержки, чтобы ускорить запросы для CRUD-опреаций на 2-3 порядка, почему-то оправдано. А вопрос был о том, почему.
Например, кто первый ответит на заявку, оперативно и достаточно точно спрогнозировав её доходность и сроки исполнения
Непонятно, что это за заявки, и как ответ базы 100ms вместо 10 мешает пользователям вашей системы делать прогнозы.
Вы неявно предполагаете, что увеличить сложность поддержки, чтобы
ускорить запросы для CRUD-опреаций на 2-3 порядка, почему-то оправдано. А вопрос был о том, почему.
Потому что для пользователя разница между получением ответа через несколько секунд или несколько десятков минут определяет, захочет ли он вообще этой системой пользоваться.
Непонятно, что это за заявки
Да не важно. Любые заявки подразумевающие приоритезацию по очередности отклика на них.
как ответ базы 100ms вместо 10 мешает пользователям вашей системы делать прогнозы.
Во-первых, прогнозы делает не пользователь, а система. Во-вторых, в реальной жизни за 100 мс оптимизационную задачу не решите, даже если десятки миллионов прогнозов и путей в графе просчитаны заранее и хранятся в БД. При решении оптимизационной задачи реакция системы от порядка секунд, если прогнозы не требуют обновления, до порядка десятков секунд, если нужно обновлять прогнозы.
Просто представьте себе задачу, где полтерабайта оперативки и 256 ядер для PostgreSQL мало, даже не смотря на то, что запросов (вызовов хранимых процедур) он получает всего десятки в секунду, а целый ряд агрегаций отданы на откуп ClickHouse. Вы всерьёз предлагаете нарастить мощность такого кластера на порядок, чтобы сэкономить несколько часов работы разработчика?
Потому что для пользователя разница между получением ответа через несколько секунд или несколько десятков минут
Разговор был про обычные CRUD-операции, обычно это означает, что пользователь делает одну CRUD-операцию за одно взаимодействие с системой (условная кнопка "Сохранить"). Они не занимают десятки минут.
Если у вас какая-то сложная обработка данных, то не проще ли ее распараллелить в коде приложения на 1000 потоков?
Если обработка простая, но данных много, то возможно да, тащить их в приложение нецелесообразно, но таких проектов мало, и непонятно, зачем проекты другого рода делать так же. Вы усложняете поддержку, но получаете профит, а в других проектах поддержка усложнится, а такого профита не будет.
Во-вторых, в реальной жизни за 100 мс оптимизационную задачу не решите
Было утверждение "Обычные crud операции можно реализовать как ХП", я спросил "Нафига?". При чем тут оптимизационные задачи?
Вы всерьёз предлагаете нарастить мощность такого кластера на порядок, чтобы сэкономить несколько часов работы разработчика?
Нет, я задавал вопрос про обычные CRUD-операции.
Разговор был про обычные CRUD-операции, обычно это означает, что пользователь делает одну CRUD-операцию за одно взаимодействие с системой (условная кнопка "Сохранить").
И я об этом же. Пользователь запрашивает, будет ли положительная доходность от конкретной заявки, если один из ста тысяч своих вагонов, в зависимости от их расположения, загрузки, движения, технического состояния и стоимости переадресации он направит на станцию погрузки заявки, перевезет груз на станцию разгрузки и направит на станцию следующей заявки или отстоя. И это всё вполне ограничивается CRUD операциями. Никаких иных запросов к БД при этом не происходит.
А сохранения заказа на закупку (условная кнопка "Сохранить") с резервированием единиц комплектующих и материалов на складах и расчетом сроков исполнения этого заказа с учетом SCM и загрузки оборудования - тоже содержит только CRUD операции. И если это заказ на закупку, например, шагающего экскаватора, то сохраняться он вполне может минуты.
Они не занимают десятки минут.
Какие десятки минут? У меня полный перерасчет прогнозирования занимает свыше 30 часов. Один SQL запрос трансформации истории операций миллиона грузовых вагонов (сейчас около 1.4 миллиона в сети РЖД) за последние пять лет во временные серии выполняется час на 24 ядрах. Больше бессмысленно выделять, так как СХД не справляется.
Если у вас какая-то сложная обработка данных, то не проще ли ее распараллелить в коде приложения на 1000 потоков?
Подняв 1000 соединений с СУБД? Или сначала загрузить десяток терабайт из БД в приложение, а потом уже параллелить их обработку? Причем далеко не все запросы вообще-то параллелятся.
Было утверждение "Обычные crud операции можно реализовать как ХП", я спросил "Нафига?".
Вы искренне считаете, что хранимая процедура обязательно должна содержать не только десятки или сотни CRUD операций, но еще что-то другое? Или для Вас одна транзакция - это всегда один SQL запрос?
При чем тут оптимизационные задачи?
Потому что без них ни один вид бизнеса не обходится. Само название ERP, подразумевает решение оптимизационных задач в целях планирования ресурсов предприятия.
И я об этом же.
Нет, не о том же. Объем вычислений за одно действие пользователя в вашем примере не такой, какой происходит при нажатии кнопки "Сохранить" в обычной админке.
Почему-то не получается ни у кого обсуждать нормально без подмены понятий.
И это всё вполне ограничивается CRUD операциями.
А я сказал про одну операцию. Именно потому что в БД вообще всё сводится только к CRUD-операциям со строками в таблицах. Поэтому различие сводится только к количеству таких операций за одно действие пользователя.
И если это заказ на закупку, например, шагающего экскаватора, то сохраняться он вполне может минуты.
Ну и пусть сохраняется. Это никак не отменяет факта, что в большинстве админок, интернет-магазинов и других аналогичных приложений сохранение данных столько не занимает. Пример - отправление коммента на Хабре.
Какие десятки минут?
Я повторил ваши слова, не знаю какие десятки минут вы имели в виду.
"Потому что для пользователя разница между получением ответа через несколько секунд или несколько десятков минут"
Подняв 1000 соединений с СУБД? Или сначала загрузить десяток терабайт из БД в приложение, а потом уже параллелить их обработку?
Для разных задач может быть по-разному.
Вы искренне считаете, что хранимая процедура обязательно должна содержать не только десятки или сотни CRUD операций, но еще что-то другое? Или для Вас одна транзакция - это всегда один SQL запрос?
Ни то, ни другое. Не вижу никакой связи с моими словами.
Разговор был о том, что вместо простого INSERT надо делать процедуру, которая будет делать INSERT, и вызывать из приложения ее. Вместо простого DELETE надо делать процедуру, которая будет делать DELETE, и вызывать из приложения ее. И т.д.
- в реальной жизни за 100 мс оптимизационную задачу не решите, даже если десятки миллионов прогнозов и путей в графе просчитаны заранее и хранятся в БД
- При чем тут оптимизационные задачи?
- Потому что без них ни один вид бизнеса не обходится.
Это ложь, я работал в компаниях, где не было десятков миллионов прогнозов и путей в графе, и большинство запросов к базе занимало меньше 100ms.
Объем вычислений за одно действие пользователя в вашем примере не такой, какой происходит при нажатии кнопки "Сохранить" в обычной админке.
Но даже меньше, чем при нажатии кнопки "Сохранить" в обычной ERP, что я специально показал. Сколько пользователей работают с ERP, а сколько с админками?
Пример - отправление коммента на Хабре.
То есть объединить в одном запросе SELECT и INSERT можно, а больше уже нельзя? )))
А любой интернет-магазин, сохраняющий в одной транзакции и заголовок заказа, и его детали - уже обходится без CRUD операций? )))
А я сказал про одну операцию. Именно потому что в БД вообще всё сводится только к CRUD-операциям со строками в таблицах.
Один SQL запрос, в общем случае, содержит одновременно INSERT, UPDATE, DELETE и SELECT, Вы действительно считаете, что это уже не CRUD операции?
Разговор был о том, что вместо простого INSERT надо делать процедуру, которая будет делать INSERT, и вызывать из приложения ее.
Нет, разговор был о том, что объединить целый ворох SQL запросов одной транзакции в одну процедуру логичней, чем интегрировать их в код на языке приложения.
не знаю какие десятки минут вы имели в виду. "Потому что для пользователя разница между получением ответа через несколько секунд или несколько десятков минут"
Которые Вы предложили, согласившись на падение производительности на два-три порядка.
"Подняв 1000 соединений с СУБД? Или сначала загрузить десяток терабайт из БД в приложение, а потом уже параллелить их обработку?"
Для разных задач может быть по-разному.
А вот тут просьба подробней. Как по первому, так и по второму вопросу. С примерами.

Ярчайший пример демагогии выделяю скриншотом. Для истории. На мой взгляд - просто шедевр, когда утверждение, что "ни один вид бизнеса не обходится без оптимизационных задач", оппонент пытается опровергнуть уже не видами бизнеса, а конкретными компаниями, да еще и апеллируя к тому, что до этого было после слова "даже".
Потрудитесь назвать вид бизнеса, который обходится без оптимизационных задач. Даже в овощном ларьке их приходится решать, пусть даже используя человеческий интеллект, вместо компьютера.
Hidden text
Сколько пользователей работают с ERP, а сколько с админками?
Понятия не имею, у нас разговор про архитектуру кода проекта, а код один для всех пользователей сервиса.
- Объем вычислений за одно действие пользователя в вашем примере намного больше, чем в обычной crud операции в админке.
- Но даже меньше, чем при нажатии кнопки "Сохранить" в обычной ERP.
Я не понимаю смысл этих слов.
сохраняющий в одной транзакции и заголовок заказа, и его детали - уже обходится без CRUD операций?
Нет.
Один SQL запрос, в общем случае, содержит одновременно INSERT, UPDATE, DELETE и SELECT
Нет, в общем случае он не содержит эти операторы одновременно.
Потрудитесь назвать вид бизнеса, который обходится без оптимизационных задач.
Не буду, потому что это не относится к вопросу, зачем обычные crud операции реализовывать как ХП.
То есть объединить в одном запросе SELECT и INSERT можно, а больше уже нельзя?
По условиям утверждения "обычные crud операции можно реализовать как ХП" нельзя. Потому что тогда это будет не обычная crud операция.
разговор был о том, что объединить целый ворох SQL запросов одной транзакции в одну процедуру логичней
Я не знаю, где вы увидели это разговор. Я спрашивал про утверждение "обычные crud операции можно реализовать как ХП, и вызывать их, просто передавая параметры в ХП". Редактирование полей одного объекта в админке это обычная crud операция. Анализ десятков миллионов прогнозов и путей в графе это не обычная crud операция.
- Я повторил ваши слова про десятки минут
- Которые Вы предложили
Нет, фраза "несколько десятков минут" впервые появляется в вашем комментарии. Похоже, вы не следите за дискуссией и спорите о чем-то своем.
На нашем среднем сервере один запрос из приложения к базе занимает порядка 0.4-2 миллисекунды. Разница на 3 порядка это 2 секунды. А не десятки минут.
И это я посчитал время целиком с передачей по сети из базы в приложение, а не только сам запрос. А с процедурой время передачи по сети останется таким же, и разница будет еще меньше.
А вот тут просьба подробней. Как по первому, так и по второму вопросу. С примерами.
Это оффтоп, поэтому подробно останавливаться не буду. Ресайзинг изображений, ссылки на которые находятся в БД. Решение задачи коммивояжера для большого количества небольших наборов координат. Индексация большого количества данных из одного хранилища для полнотекстового поиска, который обеспечивается другим хранилищем, которое принимает данные в stdin.
когда утверждение, что "ни один вид бизнеса не обходится без оптимизационных задач", оппонент пытается опровергнуть уже не видами бизнеса, а конкретными компаниями
Потому разговор был о том, как организованы конкретные проекты в конкретных компаниях, которые отправляют запросы к конкретным базам. Я спросил, почему их надо делать именно так, как посоветовал автор начального комментария. Если вы поменяли тему разговора, никому не сказав, то не надо удивляться, что вас никто не понимает. Мысли читать никто не умеет.
Я не вижу причин, почему мне надо делать хранимые процедуры в БД для моего сервиса с web-API, если где-то в этой же компании используется 1С с хранимыми процедурами в своей БД.
На нашем среднем сервере один запрос из приложения к базе занимает порядка 0.4-2 миллисекунды. Разница на 3 порядка это 2 секунды.
Хм, а ведь это даже неправильно. Это уже запрос из приложения в базу, который якобы должен быть больше на 3 порядка. То есть с процедурой должно быть 2 микросекунды, что явно неправдоподобно. В базе этот запрос выполняется за 0.3 - 1.8 миллисекунды.
Понятия не имею
Не знаете даже примерно соотношение между пользователями администраторами? Ну-ну )))
Я не понимаю смысл этих слов.
Перечитайте себя:
Объем вычислений за одно действие пользователя в вашем примере не такой, какой происходит при нажатии кнопки "Сохранить" в обычной админке.
А что происходит за одно действие пользователя я писал: "сохранения заказа на закупку (условная кнопка "Сохранить") с резервированием единиц комплектующих и материалов на складах и расчетом сроков исполнения этого заказа с учетом SCM и загрузки оборудования".
Пользователи, простите, не в "админке" по одной записи сохраняют, а документы, сохранение которых требует длительных расчетов, модификаций БД и обширной транзакции.
Я не знаю, где вы увидели это разговор. Я спрашивал про утверждение "обычные crud операции можно реализовать как ХП, и вызывать их, просто передавая параметры в ХП".
И я о том же. Хранимая процедура или функция может быть содержать не только CRUD операции. И я рассматриваю именно этот случай, а не использование императивный код, использование которого в среде СУБД - вообще отдельная тема.
фраза "несколько десятков минут" впервые появляется в вашем комментарии.
Прочитайте еще раз внимательней: "Потому что для пользователя разница между получением ответа через несколько секунд или несколько десятков минут определяет, захочет ли он вообще этой системой пользоваться."
Иными словами, если вышеописанное сохранение заказа на закупку занимает в хранимой процедуре несколько секунд, то средствами ORM, если вдруг из-за кривых запросов сформированных из приложения производительность падает на 2-3 порядка, то и возникает несколько десятков минут.
На нашем среднем сервере один запрос из приложения к базе занимает порядка 0.4-2 миллисекунды.
Очень самокритично. Даже тупое сохранение одной строки заголовка и нескольких десятков строк деталей одним запросом потребует больше времени. Я уже молчу об обновлении нескольких десятков записей в версионной таблицы с tsrange и EXCLUDE USING GIST, что гарантированно потребует десятки миллисекунд.
Ресайзинг изображений, ссылки на которые находятся в БД. Решение задачи коммивояжера для большого количества небольших наборов координат.
Какое отношение вычислительные задачи, от которых безусловно нужно разгружать СУБД, имеют отношение к "1000 соединений с СУБД" или к загрузке "десяток терабайт из БД в приложение"?
Я же просил именно такие примеры.
Потому разговор был о том, как организованы конкретные проекты в конкретных компаниях, которые отправляют запросы к конкретным базам.
Именно так. И вне Вашего кругозора есть множество задач, которые требуют перемалывания одним запросом нескольких десятков многогигабайтных таблиц. Но Вы это упорно игнорируете.
Пользователи, простите, не в "админке" по одной записи сохраняют, а документы, сохранение которых требует длительных расчетов, модификаций БД и обширной транзакции.
Это ложь, у нас есть пользователи, которые в "админке" сохраняют по одной записи, и именно про эти случаи я и спрашивал.
Более того, у нас некоторые сервисы даже в большинстве продакшн-действий сохраняют только одну запись в БД.
Хранимая процедура или функция может быть содержать не только CRUD операции.
Ё-моё, еще раз повторяю - меня не интересуют такие случаи, я задавал вопрос про противоположный случай.
Очень самокритично. Даже тупое сохранение одной строки заголовка и нескольких десятков строк деталей одним запросом потребует больше времени.
Ну не верите, не надо. Это измерения для простой CRUD-операции SELECT.
В этом проекте у нас вообще нет действий, которые сохраняют несколько десятков строк в одной транзакции.
- Если у вас какая-то сложная обработка данных, то не проще ли ее распараллелить в коде приложения на 1000 потоков?
...
- Какое отношение вычислительные задачи, от которых безусловно нужно разгружать СУБД, имеют отношение к "1000 соединений с СУБД" или к загрузке "десяток терабайт из БД в приложение"?
Потому что мое утверждение, для которого вы спрашивали примеры, было про такие задачи.
Ресайзинг изображений - запускаем 1000 процессов, они подключаются к базе, загружают каждый свою часть ссылок в память приложения, делают ресайзинг параллельно, ссылки на обработанные изображения сохраняют обратно в БД.
Решение задачи коммивояжера - аналогично.
Индексация для полнотекстового поиска - Делаем 100 воркеров, они читают по 20000 записей за раз из хранилища в память приложения, декодируют JSON, извлекают нужные поля, формируют XML, отдают в stdout, к которому подключен stdin движка sphinx, читают еще 20000. Записей было несколько миллиардов, количество терабайт сами оцените.
Но Вы это упорно игнорируете.
Это вы игнорируете то, что я вам повторил уже много раз - меня не интересуют многогигабайтные таблицы, утверждение в начальном комментарии было про обычные crud операции, поэтому и мой вопрос был про обычные crud операции. Зачем люди используют процедуры для многогигабайтных таблиц, я и так знаю.
Это ложь, у нас есть пользователи, которые в "админке" сохраняют по одной записи
Поздравляю с созданием дырявой и кривой системы. Будем считать систему с доступом пользователей к административным функциям исключением подтверждающим правило.
меня не интересуют такие случаи, я задавал вопрос про противоположный случай
И я всё время говорю о хранимых процедурах и функциях содержащих только CRUD операции. То что Вы этого не замечаете - Ваши личные проблемы )))
В этом проекте у нас вообще нет действий, которые сохраняют несколько десятков строк в одной транзакции.
Я видел ссылку на этот "проект". Одна только история изменений в JSON заставит Кодда в гробу перевернутся. Я уж молчу о том, что в реальной жизни заказы покупателей должны привязываться к SKU именно с теми характеристиками и себестоимостью, которые были реально в заказе. Причем без дублирования характеристик SKU в строках заказа. Легче перечислить требования минфина и МСФО, которые на такой структуре данных соблюдаются, чем те, которые нарушены.
Ресайзинг изображений - запускаем 1000 процессов, они подключаются к базе
Только на этом этапе потеряете в производительности уже на 2-3 порядка, заставив PostgreSQL выполнять fork() тысячу раз. Даже в сценариях, когда к PostgreSQL снаружи могут возникнуть тысячи соединений, применяют pg_bounce, радикально снижающий нагрузку на СУБД.
Решение задачи коммивояжера - аналогично.
Вы сами пробовали решать, например, на Gurobi? Это же дискретка! Seymour туда не прикрутите. На 4 потоках выигрыш в 1.5 раза, на 16 - в 2 раза. Большее количество потоков уже не дают никакой выгоды. Зачем там 1000?
У меня на Gurobi всего 15 периодов для вагонного парка из 100 тыс. вагонов считаются больше часа, при том что данные в модель грузятся несколько секунд. Там вообще нет смысла больше 4 соединений с БД поднимать.
Индексация для полнотекстового поиска - Делаем 100 воркеров, они читают по 20000 записей за раз из хранилища в память приложения,
А теперь дайте ссылку на СХД, который способен обеспечить хотя бы 4 ядрам утилизацию около 90% при тупом чтении ими записей из таблицы. У меня на очень хорошем СХД даже 4 ядра при таком сценарии утилизируются менее, чем на 70%:

И это без передачи по сети, просто в память через dblink. Одно ядро на этом сервере тянет почти 10 ГБ в секунду. По сети это уже в 100-гигабитку с трудом влезет. Только одно ядро!
декодируют JSON
О JSONB и GIN индексе ничего не слышали?
меня не интересуют многогигабайтные таблицы, утверждение в начальном комментарии было про обычные crud операции
Вы хотите сказать, что с многогигабайтными таблицами работают не CRUD операциями? Какими же тогда? Просвятите.
И я всё время говорю о хранимых процедурах и функциях содержащих только CRUD операции.
Понятно, вы не хотите слушать собеседника. Мне это не интересно.
Надеюсь, хотя бы код для тысяч документов сможете написать, как вы сами предложили ниже? Или тоже будете увиливать "Я говорил не про то, а про это, а вы не заметили"?
Понятно, вы не хотите слушать собеседника. Мне это не интересно.
Самокритично )
Надеюсь, хотя бы код для тысяч документов сможете написать, как вы сами предложили ниже?
Если бы подобный код я не писал уже десятки раз, то такого примера и не приводил.
Я спрашивал не про ваши способности в принципе, а про ваше предложение "Может вы попробуете на PHP?". Пишите свою версию на SQL, выкладывайте, попробую на PHP. Сможете?
Свою версию я писал на заказ и она принадлежит не мне. Поэтому выложить я её ну никак не могу. Даже описание процесса от бизнеса выложить не могу, так как оно содержит целый ряд know-how, позволяющих минимизировать ошибки сопоставления.
Могу разве что предложить Вам самому, для примера, получить доступ к ЭТРАН и дислокации вагонов, например из АСОУП-3. И попробовать сопоставлять хотя бы сотню вагонов. После того, как корректно удастся сопоставлять хотя бы 90% операций и накладных, к Вам придет осознание, а что же будет, если сопоставлять надо будет 100 тыс. вагонов. Я уже не говорю о 1.4 миллионах грузовых вагонов по всей сети РЖД.
Там сразу увидите, что по сравнению с bulk операциями заливки этих массивов в БД и последующей обработки в оперативке СУБД, долбление запросами через ORM даст провал в производительности на несколько порядков.
Я и не просил вас выкладывать код реального проекта, читайте внимательно.
А я приводил пример реального проекта. А если Вы хотите, чтобы я написал и опубликовал его аналог, то просьба в личку, где обсудим стоимость такой услуги.
Ну вот, сами написали "Может вы попробуете", а теперь сливаетесь. Зачем предлагали тогда, если делать не хотите.
А я приводил пример реального проекта.
А зачем вы его приводили, если та ветка была о предложении написать код и сравнить? Опять какой-то оффтоп.
Ну вот, сами написали "Может вы попробуете", а теперь сливаетесь. Зачем предлагали тогда, если делать не хотите.
Я то уже сделал. А бизнес требования я дал. Берете данные ЭТРАН, берете данные АСОУП-3 и сопоставляйте, выполняя привязку операций с вагонами к конкретной накладной. Изначально от бизнеса так задача и звучала. А уже как выбрать накладную, к которой с наибольшей вероятностью относится каждая операция - оставляю на Ваше усмотрение.
А зачем вы дали бизнес-требования, если разговор был про пример кода?
Нет, пример кода для сравнения вы не сделали.
А зачем вы дали бизнес-требования, если разговор был про пример кода?
Это кто писал?

Вот и я дал бизнес-требования. На SQL код у меня уже написан. Когда Вы напишете на PHP - сравним.
Опять вырываете фразы из контекста? Никак у вас не получается конструктивно обсуждать. Вы думаете, никто не заметит что-ли, и все будут считать вас победителем в споре?
В том же комментарии есть фраза "Реализацию на PHP я уже написал, ссылка на репозиторий есть в статье". То есть я привел код на PHP, показал его всем, и предложил сделать то же самое на SQL.
Вы сказали "А может наоборот?". "Наоборот" это значит, что вы приведете код на SQL, покажете его всем, а я сделаю то же самое на PHP. Я согласился. Раз предложили, то делайте. Или признайте, что вам слабо, и вы поторопились с этим предложением.
Мне не нужен Ваш код. Мне нужны результаты его выполнения и профилирование. Постановка задачи есть. Не можете или не хотите - так и признайтесь.
Я честно говорю, что постановку, подобную приведенной Вами, никакого смысла реализовывать в хранимой процедуре нет. Там вообще нет операций с группами записей. Если бы хотя бы SKU были расписаны группой таблиц со складами, номерами серий/партий, датами производства и срока годности - вот тогда уже вставка одного SKU одним запросом стала бы существенно выигрывать перед вставкой их десятками или сотнями запросов. Но для Вашего интернет-магазина же наплевать, на каких складах и сколько есть товарных позиций с каким сроком годности и за какое время их можно доставить покупателю в указанное им местоположение.
А вот в моей постановке провал в производительности с Вашим подходом я ожидаю на порядки.
Не можете или не хотите - так и признайтесь.
Я уже несколько раз сказал, что не хочу. Я хочу получить пример кода, я написал об этом сразу в том комментарии.
Мне не нужен Ваш код. Мне нужны результаты его выполнения
Пфф, пожалуйста. Процедура в базе занимает 10 секунд, параллельная обработка в приложении на 10 потоков 3 секунды. Что дальше?
Я честно говорю, что постановку, подобную приведенной Вами, никакого смысла реализовывать в хранимой процедуре нет
Ну и я об этом же говорю. Нет смысла делать такую логику в хранимых процедурах, это усложнит код и не принесет пользы.
Я хочу получить пример кода
Хотеть не вредно. Я Вам уже объяснил, почему публиковать этот код не буду.
Пфф, пожалуйста.
Нет журнала профилирования. Не вижу результатов в виде таблицы с сопоставлениями. Не указан ни список накладных, ни номера вагонов, участвующих в тесте. Соответственно, я никак не могу проверить результат. Значит опять лжете.
Нет смысла делать такую логику в хранимых процедурах, это усложнит код и не принесет пользы.
Нет смысла еще потому, что никакой практической ценности у этой постановки нет, что я уже не раз объяснял выше. В том числе и в том комментарии, на который Вы отвечали. Кому нужен интернет-магазин, который не может гарантировать ни сроки, ни даже само исполнение заказа?
Хотеть не вредно.
Я Вам уже объяснил, почему публиковать этот код не буду.
Ну я же говорю, сплошная демагогия.
Я вас изначально вообще-то и не просил, вы сами ответили на мое предложение написать код. Я сказал "Вот код на PHP, кто хочет может написать на SQL", вы сказали "Может наоборот?", я сказал "Давайте", теперь вы уже и наоборот не хотите. Не хотите писать код, не надо было отвечать.
Не вижу результатов в виде таблицы с сопоставлениями.
Ну так вы же не сказали, в каком виде вам нужен результат. Что просили, то и получили.
Соответственно, я никак не могу проверить результат.
Вот как раз чтобы проверить результат, люди для бенчмарков прикладывают код. Чтобы не выяснять 3 дня, кто что и как проверял. Жаль, что вы этого не понимаете.
Кому нужен интернет-магазин, который не может гарантировать ни сроки, ни даже само исполнение заказа?
Блин, объясняю еще раз для тех кто в танке. Система, которая описана в моей статье, это не интернет-магазин, и заказов там нет. Вообще, в принципе, и не было никогда. Бизнес-область приложения описана фразой "Есть отдельный сервис для поставщиков товаров". Заказы находятся не в сервисе для поставщиков, а в интернет-магазине, это другая система с другим кодом и базой, она в статье не описана.
Не хотите писать код
Код написан. Данные ЭТРАН и АСОУП-3 одинаковы для всех. Сколько гигабайт сможете выкачать, ровно тот же объем я и сопоставлю для сравнения.
Вот как раз чтобы проверить результат, люди для бенчмарков прикладывают код.
Только если речь идет об open source. Вот Вы сами упоминали задачу коммивояжера. Откуда, например, взялись сравнения производительности Gurobi и IBM Simplex, если их код не публиковался?
Ну так вы же не сказали, в каком виде вам нужен результат.
Я просил результаты выполнения кода. А по постановке задаче - это выполненные сопоставления. Что тут непонятного?
это не интернет-магазин
"Есть отдельный сервис для поставщиков товаров"
Зачем так нагло лгать?

В двух строках слово "интернет-магазин" повторяется ТРИЖДЫ!
Ладно, так как квалификации для обработки данных ЭТРАН и АСОУП-3 Вам явно не хватает, попробуйте хотя бы посоревноваться на PHP с простейшей процедурой сохранения заказов:
Hidden text
CREATE TABLE customer (
id serial PRIMARY KEY,
external_id varchar NOT NULL UNIQUE,
last_order varchar NULL
);
CREATE TABLE order_header (
id serial PRIMARY KEY,
order_num varchar NOT NULL UNIQUE,
customer_id integer NOT NULL REFERENCES customer(id),
order_date date NOT NULL
);
CREATE TABLE order_details (
id serial PRIMARY KEY,
order_id integer NOT NULL REFERENCES order_header(id),
line_num integer NOT NULL,
sku integer NOT NULL,
price decimal(13,2) NOT NULL,
qty integer NOT NULL
);
CREATE INDEX order_details_order_id_idx ON order_details(order_id);
CREATE TYPE details_compose_tp AS (
sku integer,
price decimal(13,2),
qty integer
);
CREATE TYPE order_compose_tp AS (
external_id varchar,
order_num varchar,
order_date date,
order_details details_compose_tp[]
);
CREATE OR REPLACE FUNCTION save_order (
customer_order order_compose_tp
) RETURNS varchar AS $function$
WITH OrderNum AS (
INSERT INTO customer AS C (external_id, last_order)
SELECT (customer_order).external_id,
(customer_order).external_id
||EXTRACT(YEAR FROM transaction_timestamp())::text
||'/000001'
WHERE (customer_order).order_num IS NULL
ON CONFLICT (external_id) DO UPDATE SET
last_order=C.external_id
||EXTRACT(YEAR FROM transaction_timestamp())::text
||'/'
||RIGHT('00000'||(
CASE WHEN regexp_substr(
C.last_order,
'\d{4}(?=/)')::integer
= EXTRACT(YEAR FROM transaction_timestamp())
THEN
COALESCE(regexp_substr(
C.last_order,
'(?<=/)\d+'),'0')::integer+1
ELSE '000001' END)::text,6)
RETURNING last_order ),
Hdr AS (
INSERT INTO order_header (order_num, customer_id, order_date)
SELECT COALESCE((customer_order).order_num, O.last_order),
C.id, (customer_order).order_date
FROM customer C
LEFT JOIN OrderNum O ON true
WHERE C.external_id=(customer_order).external_id
ON CONFLICT (order_num) DO UPDATE SET
customer_id=EXCLUDED.customer_id,
order_date=EXCLUDED.order_date
RETURNING id, order_num ),
DelDets AS (
DELETE FROM order_details AS D
USING Hdr H
WHERE (customer_order).order_num IS NOT NULL AND H.id=D.order_id ),
Dets AS (
INSERT INTO order_details
(order_id, line_num, sku, price, qty)
SELECT H.id, D.line_num, D.sku, D.price, D.qty
FROM Hdr H
CROSS JOIN unnest((customer_order).order_details) WITH ORDINALITY
D(sku, price, qty, line_num) )
SELECT H.order_num
FROM Hdr H;
$function$ LANGUAGE SQL;
Для ориентировки. У меня время создания сотни заказов, содержащих по сотне строк занимает 72-75 мс. А на сотню модификаций заказов из ста строк уходит 120-122 мс. Как видите, все в рамках заявленных Вами 0.4-2 мс на запрос.
И заметьте, не тревожа Кодда, я массивы и композитные типы использую только для обработки данных, но не для хранения в БД. И да, если как в Вашей публикации отказаться от внешних ключей, то производительность вырастет в 3 раза.
Код написан.
Я уже сказал, что мне не нужен код вашего реального проекта. Предложение было написать код примера и выложить, чтобы его можно было запустить самому, проверить производительность, и переписать на другом языке. Он не обязательно должен быть такой же, как в реальном проекте.
я массивы и композитные типы использую только для обработки данных, но не для хранения в БД
Если вы хотите обсудить архитектуру, пишите полное законченное приложение. Тогда может до вас дойдет, зачем для этих значений нужен JSON. Да, без него тоже можно сделать. Но толку от этого не будет.
Наконец-то вы написали хотя бы какой-то код, проверю и напишу по результатам позже.
И да, если как в Вашей публикации отказаться от внешних ключей
В базе системы из моей публикации есть внешние ключи.
В двух строках слово "интернет-магазин" повторяется ТРИЖДЫ!
Вот и читайте внимательно, что там написано. Две строки прочитать не можете. Слышу звон, да не знаю где он. Еще можете прочитать в словаре определение слова "контекст".
Да, там слово "интернет-магазин" повторяется трижды. Нет, это не значит, что указанная там система это интернет-магазин.
Ваша процедура работает быстро, только неправильно. Когда кастомера нет в базе и номер заказа null, кастомер создается, а заказ нет. Процедура возвращает null.
Хороший пример, что логика в процедурах увеличивает вероятность багов. Которые потом кто-то должен исправлять, а компания должна за это платить.
Более того, этот случай подвержен состоянию гонки. Для проверки можно добавить PG_SLEEP() в создание кастомера и отправить 2 запроса одновременно, не создадутся оба заказа, а финальный customer.last_order будет '000002'.
Когда кастомера нет в базе, и номер заказа не null, но его нет в базе, заказ и кастомер не создаются. Процедура возвращает null без какого либо описания ошибки.
Если же кастомер есть в базе, и номер заказа не null, но его нет в базе, то создается новый заказ с указанным номером. Неконсистентное поведение, которое тоже похоже на баг, надо либо в обоих случаях создавать, либо в обоих не создавать.
Более того, этот случай тоже подвержен состоянию гонки. Для проверки можно добавить PG_SLEEP() в создание заказа и отправить 2 запроса с 3 товарами одновременно. Будет создан 1 заказ с указанным номером и 6 товарами. И это уже серьезно, такую систему нельзя допускать в эксплуатацию.
Спасибо за наглядный пример, к чему приводит логика в базе. Даже специалисты с опытом разработки в БД в такой простой задаче не могут написать корректный код. Пусть приложение работает медленнее, зато правильнее.
Также эта процедура почему-то позволяет подменять владельца существующего заказа. То есть может быть заказ "customerA2024/000002", принадлежащий кастомеру "customerB". Уж не знаю, баг это или фича.
У вас код процедуры 46 строк, у меня 43, и при этом у меня много пустых строк для читаемости. Если написать сплошным текстом как у вас, то будет 31 строка. То есть кода меньше на 30%. К тому же у меня нет багов параллельной обработки.
Для проверки производительности я запустил из браузера 100 запросов, по 4 штуки одновременно, в каждом заказе 100 товаров. Как можно было ожидать, приложение оказалось медленнее. Получились такие результаты:
Среднее время работы логики на сервере (ms):
APP: 207
SQL: 14
Среднее время выполнения запроса на клиенте (ms):
APP: 563
SQL: 376
Для одиночных запросов с небольшим количеством товаров получается так:
Среднее время работы логики на сервере (ms):
APP: 70
SQL: 10
Среднее время выполнения запроса на клиенте (ms):
APP: 200
SQL: 140
Процедура на сервере в 10-20 раз быстрее приложения (различие зависит от количества товаров, для 1000 товаров будет еще больше). Но так как надо еще передать результаты работы процедуры потребителю (в данном случае браузеру), то это время тоже стоит учитывать. И для потребителя разница получается всего в 1.5 раза, что не так уж много. Для консольной команды, которая работает на сервере и обрабатывает много заказов, процедура конечно будет значительно быстрее.
Но так как эта процедура неправильно работает при параллельных запросах, в такой статистике нет большого смысла. Если добавлять защиту, время работы процедуры будет другим.
В приложении можно было использовать массовый INSERT, тогда различие было бы меньше, но я не стал.
Код можно найти здесь.
Думаю, этот пример дает достаточно информации, чтобы каждый мог сделать вывод, нужно ли ему в своем проекте делать ускорение работы таким способом, и к чему это может привести.
Все же интересно. Запрос в котором различные подзапросы и LATERAL опущены, но подразумеваюся:
WITH S1 AS (
SELECT ... ),
S2 AS (
SELECT ... ),
U1 AS (
UPDATE ...
RETURNING ... ),
D1 AS (
DELETE ...
RETURNING ... ),
I1 AS (
INSERT ...
SELECT ...
RETURNING ... ),
I2 AS (
INSERT ...
SELECT ...
RETURNING ... ),
SELECT ...
Это CRUD операции или императивный код?
Вы хотите сказать, что с многогигабайтными таблицами работают не CRUD операциями? Какими же тогда?
"Обработка одним запросом нескольких десятков многогигабайтных таблиц" это не обычная CRUD-операция. Обычная среднестатистическая CRUD-операция работает с одной таблицей. Я это уже говорил, но видимо вы с одного раза не понимаете.
Вы можете иметь свое понимание слова "обычная", но я не обязан им пользоваться. Что я понимаю под словом "обычная", я повторил уже несколько раз.
А теперь дайте ссылку на СХД
Понятия не имею, как это связано с моими словами. Вы просили примеры, я привел примеры. У нас это была HBase.
- В этом проекте у нас вообще нет действий
- Я видел ссылку на этот "проект".
Нет, я вам ссылку на наш проект не давал. И никто другой не давал. И доступа вам к нашей базе мы не давали. То, что вы описываете, это не наш проект.
"Обработка одним запросом нескольких десятков многогигабайтных таблиц" это не обычная CRUD-операция.
Операция остается CRUD вне зависимости от размеров таблиц. По крайней мере в общепринятой семантике. "Обычная" - это уже откровенный субъективизм.
Обычная среднестатистическая CRUD-операция работает с одной таблицей.
Но только в Вашем крошечном мирке. Про миллионы пользователей ERP и миллиарды операциях от них я уже писал.
Понятия не имею, как это связано с моими словами. Вы просили примеры, я привел примеры.
Вы писали?
Делаем 100 воркеров, они читают по 20000 записей за раз из хранилища в память приложения,
Вот и дайте ссылку на СХД, которая позволит утилизировать 100 ядер современного серверного CPU при чтении таблицы. Или Вы делаете вид, что не понимаете, что при подобной обработке только теряете в производительности, создавая больше соединений к БД из одного приложения, чем можете утилизировать ядер?
Нет, я вам ссылку на наш проект не давал.
Хабр глючит и это не Ваша публикация?
"Обычная" - это уже откровенный субъективизм.
Этот откровенный субъективизм был в исходном утверждении (не моём), поэтому я спрашивал в его контексте.
Но только в Вашем крошечном мирке.
Да, это только в моем крошечном мирке. Я говорю только про него с самого начала. Я уже писал, что миллионы пользователей ERP и миллиарды операций от них меня не интересуют.
Вот и дайте ссылку на СХД
Я написал название в предыдущем комментарии. Читайте внимательно. Ссылки в Гугле сами найдете, чай не маленький.
Потом можете подумать о том, что воркеры работают не мгновенно, и пока один воркер обрабатывает данные, база работает с другим.
Хабр глючит и это не Ваша публикация?
1. Это моя публикация.
2. Проект, в котором я мерил время операции SELECT и про который сказал "у нас вообще нет действий, которые сохраняют несколько десятков строк в одной транзакции" это не тот проект, который указан в этой публикации.
3. JSON в публикации это не история изменений. Заказов и SKU в публикации вообще нет.
Этот откровенный субъективизм был в исходном утверждении (не моём), поэтому я спрашивал в его контексте.
Какая разница? И тот кто начинает демагогию, применяя субъективизм, и тот кто его поддерживает - одного поля ягоды.
миллионы пользователей ERP и миллиарды операций от них меня не интересуют.
Самокритично. Но не объясняет, почему Вы тогда продвигаете тут свою точку зрению другим. Ведь по Вашей же логике Вы их совсем не интересуете. Причем в миллионы раз )))
Я написал название в предыдущем комментарии. Читайте внимательно.
Где тут СХД?
Понятия не имею, как это связано с моими словами. Вы просили примеры, я привел примеры. У нас это была HBase.
Тут только попытка демагогии с подменой темы (с реляционной SQL СУБД на не реляционную NoSQL). Или Вы не знаете, что такое СХД?
Проект, в котором я мерил время операции SELECT и про который сказал "у нас вообще нет действий, которые сохраняют несколько десятков строк в одной транзакции" это не тот проект, который указан в этой публикации.
Хотя бы открыто признали, что вели тут демагогию переходя от частного к общему, беря частным вообще один конкретный проект, а не все, с которыми более-менее знакомы.
JSON в публикации это не история изменений.
Если ProductChange не история изменений, то истории изменений вообще нет, что еще хуже.
Заказов и SKU в публикации вообще нет.
Заказы в публикации явно подразумеваются, так речь идет об интернет-магазине, а SKU в терминологии Вашей статьи называется "товар", что несколько некорректно из-за неоднозначности и обобщенности слова "товар". С точки зрения SCM отслеживаются именно товарные позиции (SKU), так как жизненный цикл любого товара подразумевает его модификацию. Чрезмерно упрощенное подобие обычной SCM и описано в Вашей публикации.
Тут только попытка демагогии с подменой темы (с реляционной SQL СУБД на не реляционную NoSQL). Или Вы не знаете, что такое СХД?
Это пример проекта, который загружает гигабайты данных в приложение, про который вы спрашивали, и данные в нем хранились в HBase на нескольких серверах. Все воркеры там работали нормально без задержек. Это всё, что вам нужно знать, дальше сами думайте.
Чрезмерно упрощенное подобие обычной SCM и описано в Вашей публикации.
Молодец, догадались. Теперь подумайте о том, зачем люди вообще пишут и рассматривают упрощенные подобия чего-то.
На остальное отвечать не буду, с моей точки зрения это какие-то бессмысленные утверждения. Но вы можете продолжать считать, что вы победили в споре, сказав много умных слов.
Это пример проекта, который загружает гигабайты данных в приложение, про который вы спрашивали, и данные в нем хранились в HBase на нескольких серверах.
Зачем мне эта демагогия, если вопрос был про СХД и реляционную СУБД? Еще раз, какая СХД использовалась?
Причем я показал, что даже один процесс на одном ядре вполне способен утилизировать 100 гигабитку. Или Вы из будущего, где уже десятитерабитные сети используются для доступа приложения к БД?
Если на сервере приложения стояло даже четыре 100 гигабитных порта с выделенными маршрутизаторами до серверов, то больше четырех потоков для загрузки данных использовать на нем не имело никакого смысла.
Теперь подумайте о том, зачем люди вообще пишут и рассматривают упрощенные подобия чего-то.
Вы пропустили слово "чрезмерное". По этой публикации явно видно как то, что Вы совершенно не знакомы с теорией SCM, так и Ваша приверженность к "золотому молотку".
Зачем мне эта демагогия, если вопрос был про СХД и реляционную СУБД?
Демагогию разводите вы. Ваша просьба выглядела так: "А вот тут просьба подробней. Как по первому, так и по второму вопросу. С примерами.". Тут нет ничего про СХД. Я про СХД в том комментарии тоже ничего не говорил, поэтому непонятно, почему вы у меня про это спрашиваете. Сами придумали требование про СХД, сами и отвечайте.
Еще раз, какая СХД использовалась?
Идите в пень со своим приказным тоном.
то больше четырех потоков для загрузки данных использовать на нем не имело никакого смысла.
Ну можете оставаться в своих фантазиях, мне какое дело.
Демагогию разводите вы.
Ну мне не жалко еще скрин сделать моего ответа на Ваше утверждение:

Идите в пень со своим приказным тоном.
Можно было и иначе признать, что заврались. Но, в принципе, меня и такой ответ устраивает )))

Специально выделил скриншотом. Вы не знаете семантику выражения "в общем случае" или Вы не знаете как написать один запрос, содержащий одновременно INSERT, UPDATE, DELETE и SELECT?
Прежде чем указывать другим на знание семантики, надо бы сначала проверить самому.
Значение слова "в общем случае"
"В общем случае" - это выражение, используемое для описания ситуации или утверждения, которое применимо в большинстве условий или контекстов, но может иметь исключения или требовать уточнений для конкретных случаев.
Синонимы «в общем случае»: в целом, как правило, обычно.
"В общем случае запрос содержит" это синоним "Обычно запрос содержит". Именно поэтому ваше утверждение ложно, обычно запрос не содержит все эти операторы сразу.
Как раз "в общем случае" это совсем не "обычно" или "в большинстве случаев". Осторожней с синонимами. Это именно в общем (свойственный всем, касающийся всех. Относящийся ко всему, всем; распространяющийся на всех, всё; охватывающий всех, всё.)
может иметь исключения или требовать уточнений для конкретных случаев
Именно так. В частных случаях запрос может не содержать одновременно INSERT, UPDATE, SELECT и DELETE.
Ну и тем более, когда данное выражение используется на техническом сайте, то его семантика явно математическая или научная. И если Вы хотите вывести формулу, верную в общем случае, то извольте учесть в ней все возможные случаи.
Я привел пруф-линк на общепринятое определение, оно подтверждает мои слова. Вы пруф с вашим определением не привели, поэтому такое толкование этого выражения это ваши выдумки.
то извольте учесть в ней все возможные случаи
Вот если бы вы сказали "В общем случае запрос может содержать все операторы", то и вопросов бы не было. А вы сказали ""В общем случае запрос содержит". Нет, не содержит. Хотя и может.
"Общий случай" это то, что является общим для частных случаев. Характеристика "может содержать" является общей для разных конкретных запросов. Характеристика "содержит" не является.
Ладно, посмешили народ и хватит. Следующим шагом еще общую математическую формулу опубликуйте, которая не покрывает все случаи )))
Может еще неопределенный интеграл в общем случае можно взять без применения рядов? )))
Я привел пруф-линк на общепринятое определение, оно подтверждает мои слова.
Прочитайте его внимательней. Приведенное определение подтверждает мои слова:

Это вам нужно читать внимательнее. Вы вырвали часть предложения из контекста и пытаетесь ей что-то доказывать. Можно еще буквы в словах переставить, чтобы получились другие слова.
Слово "исключения" подразумевает, что это исключение из "чего-то". Это указано в первой части, которую вы не процитировали: "ситуации или утверждения, которое применимо в большинстве условий или контекстов". Утверждение "Запрос содержит одновременно INSERT и DELETE" верно для большинства конкретных запросов? Нет.
В общем, я привел определение, по которому можно понимать так, как понял я. Может быть в вашем смысле оно тоже где-то употребляется, но это ничего не меняет. Это оффтоп, не вижу смысла об этом спорить.
Я понимаю, что с одной стороны русский язык для Вас не родной и даже математическое определение фразы "в общем случае" Вы не знаете. А с другой стороны Вы не способны признавать свои ошибки. Так что закроем эту тему. Признать, что "в большинстве случаев" и "в общем случае" семантически разные фразы Вы не умеете.
А на досуге попробуйте все же ответить на заданный вопрос:
"Может еще неопределенный интеграл в общем случае можно взять без применения рядов?"
Исходно было "INSERT, UPDATE, DELETE и SELECT". В принципе, это можно превратить в верное утверждение заменой логической операции:
"В общем случае, запрос может сочетать INSERT, UPDATE или DELETE с SELECT"
Может, это была ошибка неносителя русского языка, для которого не очевидно, что запятая при однородных членах выражает ту же логическую операцию, что и союз перед последним членом?..
Ссылка на словарь синонимов, в котором каждый второй синоним - ошибка, - это не пруф.
Ну приводите свой, который лучше, я ж не против. Это пруф хотя бы потому, что он показывает, что я не сам придумал такое понимание этого термина.
я не сам придумал такое понимание этого термина.
Ну да, его рандомно сгенерил какой-то неуч. Таких примеров на этом сайте тьма.
А обобщённый случай - это абстракция, которая покрывает все возможные случаи. Потому его и называют "обобщённым". Так его понимают все, кто получал высшее образование на русском языке.
Разница между реальным случаем и обобщённым - как между численными и символьными вычислениями.
Понимаю, что для неносителя это может быть новостью, но надо хотя бы не из очевидной помойки данные черпать.
Если обработка простая, но данных много, то возможно да, тащить их в приложение нецелесообразно, но таких проектов мало
Очень хотелось бы ознакомиться с исходными данными и методологией оценки, которая привела к выводу, что проектов, требующих сложной обработки больших массивов данных мало.
По моему опыту разработки и внедрения ERP, автоматизации производства, логистики, АСКУЭ, биллинга коммунальных услуг и т.п - с точностью наоборот. Даже такие относительно небольшие предприятия, как Истра-Нутриция, Белая Дача или КамчатскЭнерго без этого не обходятся. Я уж молчу о предприятиях из ТОП-200 в РФ или международных холдингах. А более мелкие предприятия редко могут позволить себе заказные разработки и вынуждены обходиться коробочными решениями.
Я говорил на основании своего опыта и анализа требований в вакансиях при поиске работы.
https://www.searchlogistics.com/learn/statistics/ecommerce-statistics/
"There are currently over 26 million ecommerce sites and stores worldwide"
Можно взять эту статистику. В большинстве интернет-магазинов нет столько данных, чтобы их надо было обрабатывать процедурами на серверах с сотнями ядер. Я сомневаюсь, что предприятий уровня КамчатскЭнерго в мире больше 26 миллионов. А во многих интернет-магазинах есть еще и внутренние проекты, где тоже хранимые процедуры не используются. Еще можно поискать количество вакансий со знанием pl/sql на hh.ru.
Я говорил на основании своего опыта и анализа требований в вакансиях при поиске работы.
"There are currently over 26 million ecommerce sites and stores worldwide"
Вы сами поняли, что написали? Ecommerce - это как раз классический пример использования тех самых заказов на закупку, о которых я писал выше. Как Вы будете формировать заказ без резервирования товара на складах и прогнозирования времени его исполнения? Это даже не трогая механизмы оплаты, которые никак "простой обработкой небольших массивов данных" не реализуются.
Я сомневаюсь, что предприятий уровня КамчатскЭнерго в мире больше 26 миллионов.
Если мы оцениваем востребованность разработки, то сравнивать надо количество сотрудников. Например, в РФ в малом и среднем бизнесе занято ~28 млн. человек при общем числе занятых ~73 млн. человек.
И это даже не считая, что я указал: "более мелкие предприятия редко могут позволить себе заказные разработки и вынуждены обходиться коробочными решениями"
При этом пользователей только 1С в РФ свыше 8 миллионов. То есть, каждый десятый занятый использует "сложные обработки массивов данных" пусть даже и не всегда "больших". А если добавить сюда остальные ERP, то легко выйдем к каждому второму пользователю компьютером на рабочем месте.
Как Вы будете формировать заказ без резервирования товара на складах и прогнозирования времени его исполнения?
Я не сказал, что буду формировать заказ без резервирования товара на складах и прогнозирования времени его исполнения.
Я сказал, что есть мало проектов, где обработка данных простая, но данных настолько много, что вытаскивание и обработка их в приложении займет несколько десятков минут.
Если мы оцениваем востребованность разработки, то сравнивать надо количество сотрудников.
Нет, сравнивать надо количество проектов, потому что решение писать логику в процедурах или в приложении принимается для проекта. Вы не пишете новый проект для каждого нового сотрудника.
Оцениваем мы количество проектов, где данных настолько много, что вытаскивание и обработка их в приложении значительно увеличит время выполнения заметно для пользователя, и так делать нецелесообразно. Вы сами процитировали и выделили слово "проектов" жирным. Похоже, вы не следите даже за тем, что сами пишете, и спорите о чем-то своем.
То есть, каждый десятый занятый использует "сложные обработки массивов данных"
Ну и пусть использует. Как из этого следует, что мне надо писать свои обычные crud операции в хранимых процедурах, если любая их них занимает меньше одной секунды даже с логикой в приложении?
Я сказал, что есть мало проектов, где обработка данных простая, но данных настолько много, что вытаскивание и обработка их в приложении займет несколько десятков минут.
Данное утверждение требует доказательств. Я уже указывал выше: "пользователей только 1С в РФ свыше 8 миллионов. То есть, каждый десятый занятый использует "сложные обработки массивов данных" пусть даже и не всегда "больших". А если добавить сюда остальные ERP, то легко выйдем к каждому второму пользователю компьютером на рабочем месте."
Причем, следует отметить, что для того, что доказать, что "хранимые процедуры не нужны", Вам потребуется привести доказательство, что таких проектов вообще нет )))
Нет, сравнивать надо количество проектов, потому что решение писать логику в процедурах или в приложении принимается для проекта.
Не надо. И я указывал почему: "более мелкие предприятия редко могут позволить себе заказные разработки и вынуждены обходиться коробочными решениями"
Как из этого следует, что мне надо писать свои обычные crud операции в хранимых процедурах, если любая их них занимает меньше одной секунды даже с логикой в приложении?
Ну если Вы сами это придумали, то сами отвечайте. Я указывал, что в природе нет пока ORM, которые всегда формируют оптимальные для СУБД запросы. И хранимые процедуры и функции в этом случае являются вынужденной мерой.
А то, что Вы ни разу не встречали запросы от ORM, которые выполняются десятки минут, тогда как, после переписывания их на SQL и оптимизации, начинают выполнятся за секунды - ничего хорошего о Вашем опыте не говорит.
Данное утверждение требует доказательств
Я их привел в одном из комментариев выше.
Я уже указывал выше: "пользователей только 1С в РФ свыше 8 миллионов.
А я указывал выше, что это не имеет никакого отношения к теме необходимости процедур в БД конкретного проекта.
Я серьезно не понимаю, с какой целью вы повторяете одно и то же, игнорируя ответы.
что для того, что доказать, что "хранимые процедуры не нужны"
Я не собирался доказывать, что "хранимые процедуры не нужны". Я задал вопрос "Зачем их писать для обычных crud операций?". Если вы не можете на него ответить, то просто не отвечайте, не надо флудить пожалуйста.
Не надо сравнивать количество проектов. И я указывал почему: "более мелкие предприятия ..."
С моей точки зрения эти утверждения никак не связаны, и фраза про предприятия не является ответом на вопрос "почему".
Меня не интересуют мелкие предприятия, когда я принимаю решение, делать ли процедуры в БД для нового проекта.
А то, что Вы ни разу не встречали запросы от ORM, которые выполняются десятки минут ... - ничего хорошего о Вашем опыте не говорит.
Не вижу логики в этом утверждении. Хорошо, что я не работал с настолько плохими проектами.
Я указывал, что в природе нет пока ORM, которые всегда формируют оптимальные для СУБД запросы.
Понятия не имею, зачем вы это указывали, я про это не спрашивал.
Я спрашивал, зачем надо усложнять код, чтобы делать оптимальные для СУБД запросы, для случаев когда даже неоптимальные занимают меньше секунды.
- Как из этого следует, что мне надо писать свои обычные crud операции в хранимых процедурах?
- Ну если Вы сами это придумали, то сами отвечайте.
Так, вы похоже вообще не понимаете, о чем идет речь. Объясняю.
Пользователь N4N в этом комментарии сделал утверждение "Обычные crud операции можно реализовать как ХП, и вызывать их, просто передавая параметры в ХП".
Я спросил его "Зачем?"
Потом в ветку приперлись вы и начали рассказывать про кластеры на десятки миллионов путей в графе и количество пользователей 1С.
Этот вопрос я не придумал в прошлом комментарии, а он был изначально, и задавал я его не вам. Если не хотите на него отвечать, не отвечайте, никто вас не заставляет.
Я их привел в одном из комментариев выше.
Голословные утверждения вижу. Доказательств не вижу в упор.
Я не собирался доказывать, что "хранимые процедуры не нужны". Я задал вопрос "Зачем их писать для обычных crud операций?".
Я это подробно разъяснил.
Меня не интересуют мелкие предприятия, когда я принимаю решение, делать ли процедуры в БД для нового проекта.
И я про это. Мелкие предприятия очень редко тратят средства на заказную разработку. Поэтому подавляющее большинство проектов для средних и крупных предприятий. С соответствующими объемами данных.
я не работал с настолько плохими проектами.
Да нет. Вы никогда не сталкивались с SQL запросами, объединяющими не тривиальным способом десятки таблиц. Так как только на планирование таких запросов оптимизатором, порой, уходит свыше указанных Вами 0.4-2 миллисекунд.
Понятия не имею, зачем вы это указывали, я про это не спрашивал.
Потому что корень проблемы именно в этом.
Я спрашивал, зачем надо усложнять код, чтобы делать оптимальные для СУБД запросы, для случаев когда даже неоптимальные занимают меньше секунды
Увы, это происходит только в Вашем крошечном мирке. А в enterprise запросы от ORM длительностью в минуты или даже десятки минут я разгребаю чуть ли не ежедневно. Судя по Jira, на это я трачу в среднем почти час каждый рабочий день.
"Обычные crud операции можно реализовать как ХП, и вызывать их, просто передавая параметры в ХП". Я спросил его "Зачем?"
А я ответил: "Можно, конечно, отложив в сторону ORM, предложить .NET разработчику включить в свой код целый ворох кода на plpgsql. Но тогда не только этот разработчик, но и любой поддерживающий этот код, должен очень хорошо знать не только C#, но и plpgsql. А можно этому разработчику предоставить представления, функции или процедуры, написанные другим разработчиком, специализирующимся на plpgsql."
Увы, это происходит только в Вашем крошечном мирке.
В очередной раз повторяю, хотя не уверен, что вы способны это понять. Я как раз и спрашивал только про свой крошечный мирок. Потому что было утверждение, что я даже в своем крошечном мирке должен писать хранимые процедуры.
я даже в своем крошечном мирке должен писать хранимые процедуры.
Я такого утверждения не видел. Я утверждаю, что в любом проекте рано или поздно от ORM к СУБД начинают приходить такие запросы, что вынужденно приходится для этих (и только для этих!) запросов отказываться от ORM и переходить на SQL. А при переходе на SQL встает резонный вопрос, стоит ли интегрировать получившиеся развесистые SQL запросы в код приложения, или все же лучше их вынести в хранимые процедуры, функции или представления. Лично я предпочитаю код на разных языках разделять, а не смешивать вместе. Обоснования моего предпочтения я изложил выше уже не раз.
Я такого утверждения не видел.
Как я уже повторил много раз, в моем понимании это утверждение "Обычные crud операции можно реализовать как ХП". В моем крошечном мирке есть обычные crud операции. Значит это утверждение говорит, что в моем крошечном мирке их тоже можно реализовать как ХП. Поэтому у меня появился вопрос "Может и можно, но зачем в моем крошечном мирке это нужно?".
А Вы перечитайте внимательно, что я написал и на что Вы отвечаете:
"Я утверждаю, что в любом проекте рано или поздно от ORM к СУБД начинают приходить такие запросы, что вынужденно приходится для этих (и только для этих!) запросов отказываться от ORM и переходить на SQL."
Просто у Вас еще недостаточно опыта и каким-то чудом Вы на такое никогда не нарывались. Хотя мне кажется, что Вы хитрите, так как с терабайтами данных работаете (по Вашим же словам), а на таких объемах это вылазит почти со 100% вероятностью в течении нескольких дней активной разработки.
Ну и не верится мне, что Вы не видите, что перемалывая даже не миллион, а всего 100 тыс. строк через ORM 100 тыс. запросами даже по 0.4 мс, то получаете итог в 40 секунд, вместо сотни миллисекунд при обработке этих 100 тыс. строк на стороне сервера БД.
начинают приходить такие запросы, что вынужденно приходится для этих (и только для этих!) запросов отказываться от ORM
Да никто с этим не спорил, откуда вы это взяли?)
Просто у Вас еще недостаточно опыта и каким-то чудом Вы на такое никогда не нарывались
Ох, попробую еще один раз объяснить. Я работал в таких проектах. И даже писал логику на хранимых процедурах. Но мой вопрос был не про такие проекты, а про противоположные. Где вообще нет таких действий, где надо отправлять 100 тысяч запросов через ORM. И где даже 40 секунд в кроне раз в сутки не создает проблемы. А вы написали про посторонние вещи, которые с темой маленьких проектов не связаны. О чем я вам уже не раз сказал.
Там, где были терабайты данных, у нас была Apache HBase, потому что MySQL с миллиардами документов плохо справляется, и даже сами разработчики MySQL сказали, что быстрее не получится.
Да никто с этим не спорил, откуда вы это взяли?)
Вы хотите сказать, что Ваш вопрос не являлся спором?
Причем я именно ссылаясь на ограничения существующих ORM на него изначально и ответил.
Но мой вопрос был не про такие проекты, а про противоположные.
Перечитайте свой вопрос. Кроме "На фига?" там никаких уточнений, что речь идет исключительно про некоторые проекты, ни слова не было.
А вы написали про посторонние вещи, которые с темой маленьких проектов не связаны.
Перечитал еще раз публикацию и ни слова о размерах проектов в ней не нашел. Или Вы не публикацию тут обсуждаете, а одному Вам известный случай?
у нас была Apache HBase
Какое отношение HBase имеет к статье о хранимых процедурах? Это даже не касаясь принципиально не решаемых проблем с ACID в HBase.
Вы хотите сказать, что Ваш вопрос не являлся спором?
Мой вопрос не являлся спором с утверждением "начинают приходить такие запросы, что вынужденно приходится для этих (и только для этих!) запросов отказываться от ORM". Он являлся спором с другим утверждением.
Кроме "На фига?" там никаких уточнений, что речь идет исключительно про некоторые проекты, ни слова не было.
Потому что умные люди учитывают контекст исходного комментария, в котором написано "обычные crud операции". Я вам уже указал на то, что ваше понимание слова "обычные" не такое, как у меня. Я не знаю, почему вы ожидаете, что я должен был ориентироваться на ваше понимание, а не на свое.
Или Вы не публикацию тут обсуждаете, а одному Вам известный случай?
Ну ок, расскажу еще и это. На Хабре комментарии организованы в виде дерева. Вопросы к статье появляются на верхнем уровне дерева. Если же кто-то хочет ответить на комментарий первого уровня, он пишет дочерний комментарий на следующем уровне, для этого в комментарии есть кнопка "Ответить". Уровень комментария показывается точками возле заголовка. Я обсуждал тот случай, который задан не в статье, а в комментарии первого уровня - "обычные crud операции". Он известен не только мне, а всем, кто прочитал этот комментарий.
Какое отношение HBase имеет к статье о хранимых процедурах?
Он имеет отношение к вашей просьбе "Приведите примеры, где нужно загрузить много данных из БД в приложение, а потом уже параллелить их обработку". HBase это БД. Раньше вместо HBase была MySQL, только тип хранилища тут принципиально ничего не меняет.
Он являлся спором с другим утверждением.
Которое само собой возникло у Вам в голове? Ссылку то Вы не привели )))
"обычные crud операции"
Любой DML SQL запрос - обычная CRUD операция. Вы хотите это опровергнуть? "Each letter in the acronym can be mapped to a standard Structured Query Language (SQL) statement."
Он имеет отношение к вашей просьбе "Приведите примеры, где нужно загрузить много данных из БД в приложение, а потом уже параллелить их обработку".
И кто из нас не просто игнорирует, а подменяет контекст? )))
Ссылку то Вы не привели
Приводил в другом комментарии, и приводил цитаты много раз. Если вы не следите за дискуссией, то это ваши проблемы.
Вы хотите это опровергнуть?
Нет. Я вам так и сказал, что каждый отдельный statement из этих 4 это обычная CRUD операция. Значит утверждение было о том, что каждый из них надо делать в виде процедуры - отдельная процедура с одним INSERT в некоторую таблицу, отдельная процедура с одним DELETE, и т.д.
И кто из нас не просто игнорирует, а подменяет контекст?
Вы. Я отвечал именно на вашу просьбу, а не на что-то другое. Более того, если вам нужная именно реляционная БД, то я сделал пояснение, что сначала она там была, и "много данных" загружалось из нее в приложение. Вы об этом спрашивали, или опять будете увиливать?
Приводил в другом комментарии, и приводил цитаты много раз.
Так и запишем, где-то в Вашей голове приводили, но сослаться тут на это не получается )))
Я вам так и сказал, что каждый отдельный statement из этих 4 это обычная CRUD операция.
Вот только c CTE один запрос может вполне содержать в себе и SELECT, и INSERT, и DELETE, и UPDATE. Или это уже не "отдельный statement"? Какой тогда?
Я отвечал именно на вашу просьбу, а не на что-то другое
Полностью подменив как тему публикации про РСУБД с хранимыми процедурами, так и контекст обсуждения именно РСУБД. Что-то Вы совсем заврались. Уже не смешно.
так и контекст обсуждения именно РСУБД
Я вам сказал, что там была MySQL. MySQL это уже не РСУБД?
Также я сказал, что конкретное хранилище в этой задаче не имеет значения. Можете представить любую РСУБД, которую хотите.
Или это уже не "отдельный statement"?
Опять вырываете фразы из контекста? Я сказал "каждый отдельный statement из этих 4". Запрос со всеми этими 4 statement-ами это не один из этих 4 statement-ов.
Вы согласны, что один INSERT без CTE это обычная CRUD операция?
Я вам сказал, что там была MySQL.
Сначала, Вы вообще не назвали СУБД
Следующим сообщением написали "У нас это была HBase."
Потом опять написали "данные в нем хранились в HBase"
После четвертой (!) просьбы назвать используемую в описанном проекте СХД, Вы уже конкретно ударились в демагогию "Сами придумали требование про СХД, сами и отвечайте."
Ну и в качестве вишенки на торта, изобразили из себя подростка-партизана, отказывающего отвечать на допросе:

А то, что я писал, что даже на четырех стогигабитках больше четырех ядер Вы ну никак не сможете утилизировать на операции выгрузки данных из вообще любой БД - вообще проигнорировали.
Mожно уже считать доказанным, что написан был бред подростка:
Индексация для полнотекстового поиска - Делаем 100 воркеров, они читают по 20000 записей за раз из хранилища в память приложения,
Поэтому дальнейшие виляния и попытки запудрить мозги с MySQL уже никакой роли не играют.
Опять вырываете фразы из контекста?
Нет уж, сначала на мои прямо поставленные вопрос ответьте:
Вот только c CTE один запрос может вполне содержать в себе и SELECT, и INSERT, и DELETE, и UPDATE. Или это уже не "отдельный statement"? Какой тогда?
А уже после того, как этот момент проясним, я буду отвечать на встречные вопросы, если ответы на них еще потребуются.
Вы ну никак не сможете утилизировать на операции выгрузки данных из вообще любой БД - вообще проигнорировали.
Я проигнорировал, потому что вы проигнорировали мое описание соотношения работы сети и процессора. Никакие ваши рассуждения фактов не меняют. У нас эта система работала в 100 потоков, и производительность увеличилась примерно в 100 раз по сравнению с одним потоком, а не в 4. Значит ваши рассуждения где-то неправильные, а выяснять где мне неинтересно.
Параметров оборудования я не знаю, я программист, а не системный администратор, мне их никто не сообщал. Я только подобрал параметры приложения для оптимального использования сети и процессора. Если бы после 4 потоков не было ускорения, я бы оставил 4.
Сначала, Вы вообще не назвали СУБД
Я уже несколько раз сказал почему - потому что конкретное хранилище ничего не меняет. Но потом выяснилось, что вы этого не понимаете, поэтому я сообщил больше деталей.
Можно хранить в Postgres, и все равно для этой задачи надо будет загружать много данных в приложение и обрабатывать параллельно. Нет, встроенный полнотекстовый поиск Postgres не подходит по требованиям. Если вы не можете понять такую простую вещь, и не можете представить, как такое приложение будет работать с Postgres, то вообще нет смысла с вами это обсуждать.
сначала на мои прямо поставленные вопрос ответьте
Я уже ответил в прошлом комментарии. Похоже, вы не способны понять ответ. Ничем не могу тут помочь, хотя я попытался уже несколько раз.
У нас эта система работала в 100 потоков, и производительность увеличилась примерно в 100 раз по сравнению с одним потоком, а не в 4.
Это говорит только о чудовищно кривом коде, в котором процессы выгрузки данных из БД и обработки этих данных не были разделены. Более того, если ядер/потоков на хосте приложения было меньше 100, то это еще и незнание асинхронного программирования.
Параметров оборудования я не знаю, я программист
Первое самокритично, но из этого вытекает, что второе ложно.
Я уже несколько раз сказал почему - потому что конкретное хранилище ничего не меняет.
Еще как меняет. В среде Hadoop обработку можно вести хоть на миллионе хостах по всей планете, с огромной суммарной пропускной способностью. Google за год индексирует свыше зетабайта, что легко пересчитывается в десятки терабайт в секунду.
Я уже ответил в прошлом комментарии.
Вы уклонились от прямого ответа на прямо поставленные вопросы:
Я сказал "каждый отдельный statement из этих 4". Запрос со всеми этими 4 statement-ами это не один из этих 4 statement-ов.
В упор не вижу здесь ответа на два заданных мной вопроса.
Вот только c CTE один запрос может вполне содержать в себе и SELECT, и INSERT, и DELETE, и UPDATE. Или это уже не "отдельный statement"? Какой тогда?
Это говорит только о чудовищно кривом коде
Видимо вам все-таки проще оставаться в рамках собственных фантазий. Правда для вас слишком неудобна, и вы ее избегаете. Выдумываете всякие условия, в которых ваши утверждения будут верными.
На всякий случай поясню. Код там проще некуда, "прочитать данные, обработать, повторить", меняется только количество запрашиваемых строк в одном запросе и количество потоков.
В среде Hadoop обработку можно вести хоть на миллионе хостах по всей планете
И? В чем изменение-то способа решения задачи "отправить данные в sphinx"?
В упор не вижу здесь ответа на два заданных мной вопроса.
Я сказал, что ваш вопрос содержит фразу, вырванную из контекста, и потому некорректен. Это и есть мой ответ, другого ответа на некорректный с моей точки зрения вопрос я дать не могу.
Кто-то может привести пример, когда постоянно нужно менять сервер?
Кстати, был у меня кейс такой. Одна и та же кодовая база приложения, но может выполняться в двух разных форматах: на сервере, где висит какой-нить MySQL, и в качестве десктопного приложения, где SQLite.
И обе эти СУБД надо поддерживать одновременно
Да ответ-то на всё простой - дизайнить систему надо правильно: бизнесу - бизнесово, базе - базово. Тогда всё уляжется. Отцы-основатели ООД и ООА свое дело туго знали, не то что нынешнее племя...
Я бы сказал так.
Для юзер-ориентированных приложений, построненный по трех-уровневой архитектуре - хранимки "это рудимент". В новых приложениях использовать такие решения крайне плохо и никакая "лапша на уши" про 2% выигрыша производительности того не стоит.
Одно размазывание логики чего стоит, плюс полная невозможность переиспользования реализации в разных слоях.
------------
Но есть куча задач в самой БД либо для переливки\подготовки данных. Тут хранимки - это хорошо и правильно.
----------
Немного по пунктам
Сложность в тестировании
Для юнит тестов - наверное да, так как надо "готовить" кучу данных, что для логики в приложении как правильно не проблема (ну или как минимум легче подкинуть в тест данные). Для чего-то интеграционного данные так или иначе надо готовить, поэтому тут уже не факт, что хранимки чего-то там усложняют
Автоматическое тестирование или unit-тесты
Тут я не понял, в чем сложность. Возможно просто автор чуток не умеет в определенные вещи
Например, от бизнес-партнеров поступило требование собирать метрики по определённым участкам бизнес-процесса для их оценки. И как мы будем это делать? Правильно, реализовывать ещё больше костылей, потому что SQL — это язык для агрегации данных, а не язык для описания бизнес-логики приложения. В любом современном языке программирования достаточно подключить какую-либо библиотеку и настроить URL /metrics для сбора необходимых метрик
И да, и нет. Зависит от метрик. Ну и надо понимать, что сбор метрик в интеграционной среде часть это много разных приложений, что уже не так сильно зависит от конкретных технологий реализации
Любая категоричность а подобных вопросах - вещь сильно спорная. Вот IBM в своё время чуть не разорилась из-за злоупотребления оператором goto, и потом целое поколение программистов шарахалось от этого оператора, как чёрт от ладана. Многие даже и не знали первопричины. Просто - детская травма :-)
Второй пример из области БД: триггеры - это зло! Теперь - хранимые процедуры, как оказалось, тоже зло.
Возможно, просто надо разобраться, что для чего использовать, и в каких количествах?
"чуть не разорилась из-за злоупотребления оператором goto". Что вот прям вот это причина не использовать GOTO в коде?! 🤔 У меня как-то от тех времён другое представление осталось 😳...
Ну, чуть упростил историю про спагетти-код и ОС, которую никак не могли дописать, в результате чего появилась теория и практика структурного программирования... :-) Но запрет на goto был следствием произошедшего, нет?
Возможно... Просто я с содроганием вспоминаю свой опыт перевода небольшой части пакета Графор с Фортрана на Паскаль (ну, нужно нам было на Паскале строить какие-то графики, а самым простым способом в тех условиях было взять готовую профессиональную библиотеку и как-то частично выдрать из неё нужное). То есть, мне казалось всегда, что это всё-таки, в первую очередь, вызвано именно спецификой самого оператора, а не только лишь каким-то конкретным историческим событием.
Про "запрет" как-то странно читать, конечно, когда оператор goto спокойно себе существует даже в современных (сравнительно) структурных языках (да в с#, хотя бы). Но вот для чего он там существует - мне совершенно непонятно. Это как рекурсия - приём существует, но пользоваться им чревато...
Особенно круто проявляет себя аналог goto в машинном коде, когда всё написал, посчитал смещения для переходов и вдруг потом выясняется, что надо вставить пару-тройку команд в середине. Или в ранних версиях Бейсиков, когда при правке кода выясняется, что зазоров в нумерации строк не хватает для внесения необходимых исправлений 😁.
А плюсах я им не пользовался, а вот в С использовал регулярно, чтобы перебрасывать управление в конец функции и обрабатывать там ошибки. Вместо исключения.
Опять же, всё зависит от того, как пользоваться. Немаленькую систему написанную на Фортран II без особых проблем перевели на АСВТ Паскаль примерно в те же годы. (ПРИС)
Могу рассказать зачем goto в сишарпе) Компиляция идет в 2 этапа. Сперва код преобразуется в низкоуровневый си шарп, в котором отсутствует большинство конструкций. К примеру из циклов там есть только while, в который преобразуются все остальные. На этом этапе происходит масса оптимизаций. И только потом низкоуровневый сишарп компилируется в msil. Так вот компилятор иногда использует метки и goto в низкоуровневом коде. Это бывает при разворачивании свичей, для выхода из циклов, или вложенных конструкций, при обработке исключений. Он компилятор, ему можно. Ну и собственно поэтому goto не удаляют из спецификации языка. Хотя использовать его не-компиляторам конечно же не стоит.
Посмотреть чего там нагенерил компилятор бывает очень полезно, или хотя-бы познавательно. Можно на сторонних ресурсах, в студии через решарпер, в райдере встроено из коробки.
Увы, мода рулит всем. Но злоупотребление goto - это действительно такое себе.
Возможно, просто надо разобраться, что для чего использовать, и в каких количествах?
Так автор вроде бы так и делает? Говорит, что для бизнес-логики надо использовать код в приложении, а хранимые процедуры надо использовать в количестве 0. Приводит свои аргументы для этого утверждения.
Задача, которую я только что решал: односторонняя (слава богу) синхронизация данных Oracle -> Postgres. Можно, конечно, обойтись без stored procedures...
Вторая задача. Данные поступают из другой системы и сразу должны быть трансформированы/обогащены. Тоже можно решить без встроенных процедур и триггеров. А надо? И это - таки-часть бизнес логики.
Это связано с тем, что требования к качеству работы приложений возросли, а новых инструментов в SQL для решения этой проблемы так и не появилось, что не позволило повысить качество.
Невозможно относиться к подобным сентенциям иначе, чем к древнему "Кому сейчас нужна командная строка, если всё можно сделать мышкой". Инструмента, видите ли, нету...
Со временем, когда отцы-основатели данной хранимой процедуры покидают компанию, вместе с ними уходит и понимание того, как всё это должно функционировать. Новым сотрудникам, чтобы внести небольшие изменения, приходится собирать информацию по крупицам от тех, кто хоть как-то взаимодействовал с этим чудом инженерной мысли.
Переводя на русский - программист с хорошим знанием SQL уволился, а вместо него наняли другого, который в SQL ни ухом, ни рылом.
А виновата, как обычно, хранимая процедура.
Размазанность бизнес логики
Вот интересно, вас использование в бизнес-логике различных функций и процедур из "стандартных" библиотек не раскорячивает? Или если процедура поставляется с ОС/фреймворком/средой/прочее - то это built-in, а если сам написАл - то это бизнес-логика?
Любая бизнес-логика составлена из кучи элементарных операций. Сортировка, поиск, фильтрация, агрегация, расчёт, сравнение, выбор, и т.д., и т.п. И где-то есть та граница, после которой несколько последовательных элементарных операций становятся бизнес-логикой, специфической для конкретного процесса, хотя вот только что эта последовательность ещё была последовательностью достаточно стандартных операций, просто со специфическими константами, ограничениями и пр. И если эта последовательность переносится в хранимую процедуру, то бизнес-логика совершенно не страдает и не дробится. Просто отлаживать надо лучше, условий учитывать больше, входные проверять жёстче, документировать качественнее. Должно быть - "написал и забыл".
А SQL-сервер обрабатывает данные всяко лучше, чем программист напишет.
Переводя на русский - программист с хорошим знанием SQL уволился, а вместо него наняли другого, который в SQL ни ухом, ни рылом.
Нет, это означает, что какая-то процедура пишет в какую-то таблицу число 42, которое неизвестно что обозначает, и неизвестно кто его читает.
Вот интересно, вас использование в бизнес-логике различных функций и процедур из "стандартных" библиотек не раскорячивает?
Нет, потому что в стандартных библиотеках бизнес-логики приложения нет, и при изменении бизнес-требований их менять не надо.
а если сам написал - то это бизнес-логика?
Бизнес-логика — совокупность правил, принципов, зависимостей поведения объектов предметной области. Иначе можно сказать, что бизнес-логика — это реализация правил и ограничений автоматизируемых операций. Проще говоря, бизнес-логика — это реализация предметной области в информационной системе.
Процедура реализует правила и ограничения бизнеса - это бизнес-логика. Не реализует - не бизнес-логика. Условно говоря, бизнес-логика это код, который вы меняете при изменении бизнес-требований.
то бизнес-логика совершенно не страдает и не дробится
Если целиком перенесли, то может и не дробится. А когда одна часть в приложении, а другая в базе, то дробится.
какая-то процедура пишет в какую-то таблицу число 42, которое неизвестно что обозначает, и неизвестно кто его читает.
Ну то есть вся проблема - в хреновом документировании, что ли?
Процедура реализует правила и ограничения бизнеса - это бизнес-логика.
Вот только не надо тёплое да мягкое в одну кучу, да... Процедура реализует правила и ограничения, которые передаются в неё значениями параметров. Всё. Точка.
А вызов этой процедуры передаваемыми параметрами задаёт используемые ограничения и параметры применения правил в соответствии с требованиями бизнеса - вот сам вызов и есть бизнес-логика. Но он не на SQL сервере. а в вашем бизнес-приложении.
Вот если вы и параметры, необходимые бизнес-процессу, захардкодили в процедуре, то да, она как-то уже стала не общей процедурой, а куском вашей бизнес-логики. Но кто в том виноват-то?
Ну то есть вся проблема - в хреновом документировании, что ли?
Конкретно в этом высказывании проблема в том, что вы "перевели на русский" неправильно, с целью высмеять автора и его сторонников, на что я указал.
С кодом в приложении такого документирования требуется заметно меньше, о чем собственно и говорит автор.
Процедура реализует правила и ограничения, которые передаются в неё значениями параметров.
Нет, структура if, switch, foreach, и прочих управляющих конструкций, задающих логику, а также последовательность вызовов из кода процедуры других процедур, не передается значениями параметров.
Вы спросили, как отличить бизнес-логику от не бизнес-логики, я вам привел общепринятый критерий. Вы можете быть с ним не согласны, но фактов это не меняет. При этом в обоих случаях это процедуры с параметрами.
А вызов этой процедуры передаваемыми параметрами и есть бизнес-логика
Нет. Есть процедура "Создание заказа". Она вызывается только с id корзины, где есть список товаров. Есть бизнес-требование "Если есть товары из группы А, добавить дополнительную строку доставки 1000 рублей, потому что требуется грузчик". Его реализация это бизнес-логика. Вы это регулируете параметрами процедуры или if в коде процедуры?
Дальше появляется бизнес-требование "Если есть товары из группы Б, добавить дополнительную строку доставки 2000 рублей, потому что требуется 2 грузчика. Если при этом есть товары из группы А, то добавлять 1000 рублей не надо". Для его реализации вы добавите параметр в вызов процедуры, будете вместо id корзины передавать что-то другое, или поменяете код процедуры?
Есть процедура "Создание заказа". Она вызывается только с id корзины, где есть список товаров. Есть бизнес-требование "Если есть товары из группы А, добавить дополнительную строку доставки 1000 рублей, потому что требуется грузчик". Его реализация это бизнес-логика. Вы это регулируете параметрами процедуры или if в коде процедуры?
Я добавлю эту дополнительную строку в список товаров корзины ПЕРЕД вызовом процедуры.
Процедура должна выполнять именно операцию создания заказа по переданному ей списку товаров с количествами и вернуть результаты своей работы (номер созданного заказа либо признак/код ошибки создания заказа). Это элементарная операция за пределами бизнес-логики. Добавление же строки - это бизнес-логика, которая реализуется в коде приложения, либо до вызова процедуры добавлением нужной строки в состав корзины (в процессе создания корзины в момент добавления в неё товара группы А, либо в момент финализации создания корзины и перехода к созданию заказа), либо после неё получением характеристик созданного заказа и вызовом процедуры корректировки заказа.
С кодом в приложении такого документирования требуется заметно меньше,
Вот этого не понимаю от слова "совсем". Есть "число 42". В документировании должна быть добавлена строка, которая разъясняет, что это за значение, куда и в каком случае пишется и т.п. Объясните мне, почему эта строка в документировании приложения будет короче. чем в документировании процедуры...
Или вы хотите сказать, что в процедуре это задокументировать нужно, а в приложении нет? Ну тогда мы снова возвращаемся к тому, что новый сотрудник дока в используемом ЯП (и так знает, что это за "42") и ноль в SQL.
Есть "число 42". Объясните мне, почему эта строка в документировании приложения будет короче. чем в документировании процедуры.
В приложении нет "числа 42", есть конкретная константа с говорящим названием в каком-то классе EmailTemplate::ORDER_CREATED = 42;
, которая используется в разных функциях в коде вместо числа 42. Ее не нужно дополнительно документировать где-то еще. А в процедурном SQL такие константы сделать нельзя, максимум в каждой процедуре где нужен этот шаблон будет своя переменная SET tempateOrderCreated = 42;
. И если появится новый шаблон письма для создания заказа с другим id, то надо будет искать и менять во всех местах.
А часто в приложении вообще нет необходимости писать число 42 в какую-то таблицу, а потом его читать для какого-то действия, мы сразу вызываем нужное действие.
Процедура должна выполнять именно операцию создания заказа по переданному ей списку товаров с количествами и вернуть результаты своей работы.
У меня именно это и написано. "Создание заказа по переданному ей списку товаров" означает, что в корзине есть только список товаров, а процедура создания заказа должна сама рассчитать все необходимые платежи.
Это элементарная операция за пределами бизнес-логики.
Если у вас процедура это простая обертка для элементарной операции INSERT, то непонятно, зачем она нужна.
Я добавлю эту дополнительную строку в список товаров корзины ПЕРЕД вызовом процедуры
Добавление же строки - это бизнес-логика, которая реализуется в коде приложения
Вы же говорили про перенос бизнес-логики в хранимую процедуру:
"Любая бизнес-логика составлена из кучи элементарных операций. И если эта последовательность переносится в хранимую процедуру, то бизнес-логика совершенно не страдает и не дробится".
Если у вас часть реализации бизнес-требований находится в приложении, а часть в хранимой процедуре, то это и есть размазанность бизнес-логики. А потом программисту приложения надо разбираться, где какая часть бизнес-требований реализована, и как это всё вместе работает.
либо до вызова процедуры добавлением нужной строки в состав корзины, либо после неё получением характеристик созданного заказа и вызовом процедуры корректировки заказа.
Да-да, вот эти вот скрытые знания "Нельзя просто вызвать процедуру "Создать заказ(id корзины), перед вызовом надо добавить в эту корзину доставку", это и есть "собирать информацию по крупицам".
У бизнеса вообще нет такой операции "Добавить доставку в корзину", в корзину можно добавлять только товары и коды скидок. То есть программисту, который этот код не писал, придется разбираться, какие операции с корзиной соответствуют бизнес-требованиям, а какие программист сам придумал. Такая логика не прошла бы код-ревью ни в одной компании, где я работал. Спасибо, это хороший пример того, о чем говорится в статье.
Вы же говорили про перенос бизнес-логики в хранимую процедуру:"Любая бизнес-логика составлена из кучи элементарных операций. И если эта последовательность переносится в хранимую процедуру, то бизнес-логика совершенно не страдает и не дробится".
Нет, я ожидал неприятия и непонимания, а потому ваши возражения мне неудивительны. Но вот таких передёргиваний - выбросить кусок текста из середины так, чтобы смысл оставшегося инвертировался, и на основании полученной цитаты, заведомо не имеющей отношения к оригиналу, убеждать меня в ошибочности моего мнения,- не ожидал.
У бизнеса вообще нет такой операции "Добавить доставку в корзину", в корзину можно добавлять только товары и коды скидок.
Цитирую ваши слова: "Есть бизнес-требование "Если есть товары из группы А, добавить дополнительную строку доставки 1000 рублей, потому что требуется грузчик". Его реализация это бизнес-логика." То есть требование есть, логика есть а операции нет? Хотя строка "Доставка" финально-таки есть. Непонятно.
Но вот таких передёргиваний не ожидал.
Объяснением вы конечно себя утруждать не хотите? "Вы меня поняли неправильно, а как правильно не скажу"?
Вы написали комментарий, я с самого начала говорю в его контексте. В нем вы не говорили про бизнес-логику в приложении, а приводили аргументы в защиту логики в процедурах.
Цитирую ваши слова:
добавить дополнительную строку доставки
Так не сказано же, что надо добавить ее в таблицу корзины. Я написал "Есть процедура "Создание заказа". Она вызывается только с id корзины, где есть список товаров", значит строку доставки надо добавить в заказ при создании. Чтобы она потом отображалась пользователю, и ее можно было учитывать при возвратах. "Строка доставки" это бизнес-термин из бизнес-требований.
То есть требование есть, логика есть а операции нет?
Операции "Добавить строку доставки в корзину" нет. Есть операция "Создание заказа", одно из ее действий это добавить строку доставки в создаваемый заказ по заданным условиям.
Объяснением вы конечно себя утруждать не хотите? "Вы меня поняли неправильно, а как правильно не скажу"?
Давайте обратимся к полной версии текста.
Любая бизнес-логика составлена из кучи элементарных операций. Сортировка, поиск, фильтрация, агрегация, расчёт, сравнение, выбор, и т.д., и т.п. И где-то есть та граница, после которой несколько последовательных элементарных операций становятся бизнес-логикой, специфической для конкретного процесса, хотя вот только что эта последовательность ещё была последовательностью достаточно стандартных операций, просто со специфическими константами, ограничениями и пр. И если эта последовательность переносится в хранимую процедуру, то бизнес-логика совершенно не страдает и не дробится.
Теперь посмотрим, что вы оставили при цитировании.
Любая бизнес-логика составлена из кучи элементарных операций. И если эта последовательность переносится в хранимую процедуру, то бизнес-логика совершенно не страдает и не дробится
Итак, в исходном тексте утверждается, что есть та граница детализации, ниже которой элементарная операция или последовательность таких операций ещё не составляет элемента бизнес-логики, а является стандартной обработкой набора данных. И если такую последовательность выполнять не как набор отдельных операций, а единую агрегированную операцию, то она по-прежнему не станет элементом бизнес-логики.
А что оставили вы? Вы оставили часть текста, которая утверждает, что агрегировать можно без оглядки на такую границу.
Я говорил про контекст обсуждения, а не про конкретное высказывание, поэтому процитировал то, что задает контекст. Вы с самого начала говорили про размещение бизнес-логики в коде процедур, сказали "SQL-сервер обрабатывает данные всяко лучше, чем программист напишет", поэтому я привел пример процедуры на SQL-сервере с бизнес-логикой создания заказа. А потом вы ни с того ни с сего сказали, что бизнес-логику в этом примере надо размещать в приложении. Поэтому я указал на кажущееся мне несоответствие. Если вы согласны, что в таких случаях правильнее размещать бизнес-логику в приложении, то непонятно, с чем вы спорите тогда.
К примеру на этих ваших ms sql'лях можно .net хранимки делать, на постгресах всякие там pl/python, и тд. и тп., так что всё зависит от прокладки между...
DBA-разработчики?
Разработчики администраторы баз данных?
Капризный плач малолетнего кодера-неумехи.
Можно, конечно, пропуская картинки и абзацы с лирикой, разобрать статью по пунктам, начиная с "когда отцы-основатели данной хранимой процедуры покидают компанию, вместе с ними уходит и понимание того, как всё это должно функционировать" (если такие "отцы" напишут бизнес-логику на стороне приложения и тоже исчезнут, не оставив документации, то эффект будет ровно тот же), но смысла в этом немного, как и в том, что можно написать симметричную статью про плюсы размещения бизнес-логики на стороне БД. Задачи бывают разные, решения под них нужны тоже разные и в этом смысле в статье не хватает главного - рассказа автора о кейсах, в которых ему приходилось размещать бизнес-логику в разных компонентах ИС. А так получился неоригинальный (на мой взгляд, просто набор банальностей) и однобокий взгляд на вопрос.
Мне почему-то кажется, что в названии статьи не хватает тире перед словом рудимент. Собственно, именно поэтому и открыл, поскольку сразу не смог понять о чем речь: то ли о процедуре рудимента(кстати, а есть такая?), то ли о процедуре, как о рудименте. Впрочем, это возможное следствие затухающего сознания перед сном; в следующий раз попробую статьи с интригующим названием откладывать на утро.
Все зависит от задач и архитектуры ПО. Мало кто понимает как правильно создавать архитектуру подобных приложений с логикой на сервере. В приложениях локальной сети я использую только хранимые процедуры и функции SQLServer, на клиенте Delphi c FIREDAC и LABVIEW c ODBC. Разработка не crud приложений, а сложных систем для производства и тестирования интеллектуальных датчиков и расходомеров. Кстати, есть и приложение для ремонта интеллектуальных приборов с элементами документооборота. Все приложения включены в систему мониторинга и логирования ( без всяких Кафка, все на SQL). Логика на сервере очень удобна для меня. Но нужно правильно делать архитектуру ПО, оставляя на клиенте только интерфейсные зависимости. Все изменения DDL посредством триггера в БД логируются в таблицу БД и всегда можно посмотреть изменения не только в хранимых процедурах, а вообще все изменения в БД. Одну из систем я описал в своей статье ( можно открыть публикацию из моего профиля на хабр.
https://habr.com/ru/users/ALexKud/publications/articles/
С десктопными приложениями есть свои особенности. С логикой на клиенте надо при изменениях обновлять все клиенты, а также на языках типа Delphi работа с хешмапами сложнее, чем SQL с динамической типизацией.
Поэтому если десктопное приложение коннектится напрямую к базе, то хранимые процедуры оказываются удобнее. Но дело в том что в данном случае это просто удобство логики на сервере, и можно сделать сервер на другом языке программирования, который более удобен для выражения бизнес-требований, чем процедурный SQL. Это также и более безопасно, чем давать пользователю прямой доступ к базе.
У нас клиенты и rest сервер на Делфи, с кешированием и прочим. При этом, использование хранимых процедур сильно повышают скорость выполнения сложных, комплексных запросов. Потому что не нужно гонять данные между сервером и бд.
Ну и пусть повышают, это не противоречит моим словам. Я работал в проекте с приложением на Делфи и логикой в процедурах, указанные причины часто упоминались при решении вопроса, где делать изменения по задаче.
Почему не нужно, если это упростит поддержку, уменьшит количество багов и время выполнения задач программистами? Может быть у вас оно не упрощает, но другие-то почему должны от этого отказываться, если у них упрощает.
Ханимые процедуры не только удобнее, они в разы упрощают разработку приложений с сложной бизнес логикой. ТЗ одного приложения был на 25 страниц и там было столько всего, начиная от ввода документа и его обработки, формирования документов и протоколов метрологии и его закрытия с учетом прав доступа 5-ти подразделениям производства. У меня не было никакой команды, все делал сам начиная с архитектуры, БД и клиента. На релиз ушло 8 месяцев всего. Сейчас уже 9 месяцев эксплуатации, иногда приходится кое-что подправлять, но в основном серверную часть и иногда клиента.
Не вижу ничего плохого пользователю коннектится в серверу с такой же политикой в домене с идентификацией под Windows . Админских прав у юзеров нет, доступ к запуску хранимых процедур только через роли БД. Всегда в приложение добавляю возможность использования мониторинга коннектов всех сервисов( программ) при запуске приложения. Написано специальное приложение для такого мониторинга, которое показывает в онлайне кто и когда коннектился и что делал. Все приложения имеют логи всех операций и они отображаются в мониторинге.
ТЗ на пару десятков страниц? Да вы никак шутите) Если распечатать все бизнес-требования, которые бывают в обычном веб-приложении среднего размера, там и 100 и 200 страниц может быть. У вас ушло 8 месяцев, на PHP это можно было бы сделать наверно за неделю. Ну может за месяц.
Автор имён ввиду автономные транзакции, когда говорил о логировании. Т.е. то что имел ввиду сделать в БД можно, если только пул коннектов выдержит
Я абсолютно не против того, чтобы не пихать бизнес-логику в хранимки
Но те, кто об этом пишет статьи, обычно предлагают такие альтернативы:
аналогичный код на Питоне / JS / PHP..., ещё и обезображенный использованием ORM
dbt и его аналоги, которые в точности повторяют функционал хранимок, но через богомерзкую Jinja
Ещё ни разу не видел кейса, чтобы написали: "мы выпилили хранимки, вместо них написали высокопроизводительный код на С / Java / Rust..., который работает с данными по бинарному протоколу"
А замена хранимок на dbt / функции во внешних скриптах - это тот же половой орган, только в другой руке
--
По поводу именно этой статьи: баянистый сборник мифов о хранимках от человека, который вряд ли когда-то хотя бы пробовал писать на них что-то сложное. Иначе никак не объяснить множественные посылы о проблемах с тестированием - это ж самое простое как раз
SQL — это язык для агрегации данных, а не язык для описания бизнес-логики приложения.
А ведь дальше действительно можно не читать. Автор в корне не понимает предназначение SQL. Ну дак бог с ним. Все эти наезды на Structured English QUERY Language и рутины написанные на нем нужно отстоять. И не только с точки зрения написания бизнес-логики, но и с точки зрения жизненного цикла.
Размазанность бизнес логики
Существует класс задач, с которыми языки верхнего уровня просто не справятся. Например, ETL. А конкретно Transform and Load. Нет, можно и NIFI прикрутить. Но если вы думаете о скорости, хорошем плане выполнения, и т.д., то SQL продходит куда лучше.
Сложность в тестировании
Автор явно не гуглил прежде, чем заявлять, что нет фреймворков для написания настоящих юнит-тестов на SQL. Приведем парочку - tSQLt и pgTap. Кстати, готовлю комит в pgTap дабы расширить его функциональность в плане возможностей изоляции внутри юнит-теста.
И вообще современных приложениях стараются отвязаться от конкретного источника данных, ведь кроме конкретной SQL БД существуют и другие.
noSQL, Elasticsearch... какие модные слова! Вы теплое с мягким путаете. Разберитесь в вопросе прежде, чем писать. Все РСУБД, по сути на одном стандарте. Да, различия есть, но они преодолимы.
Проблемы с переездом на другую БД
И какие у вас проблемы? А какие такие разработчики переезжают на новый реляционный сервер БД и не при этом не знают как он работает? А вы в курсе, что в интернетах давно гуляют целые руководства по переезду? Вообще, говоря тема санкций это не тема именно РСУБД, это так на минуточку. Ничем вы РСУБД не замените, если вам нужен ACID.
В заключении могу с уверенностью утверждать, что вы не умеете "готовить" и работать с РСУБД.
"Backend разработчики должны обладать знаниями DBA". Интересно, зачем им знания DBA? Некоторым научиться бы писать простые запросы без подстказок ORM.
Наверное хайп из-за кликбейтного заголовка.
В целом автор подсветил актуальную проблему: разделение и переход на 3х звенку и дальше микро сервисы выделил класс разработчиков которые работают с БД и при этом не умеют этого делать. Автор явно пишет:
приходится вносить изменения в код без полного понимания, надеясь, что всё заработает
при этом ссылаясь на:
Со временем, когда отцы-основатели данной хранимой процедуры покидают компанию, вместе с ними уходит и понимание того, как всё это должно функционировать. Новым сотрудникам, чтобы внести небольшие изменения, приходится собирать информацию по крупицам от тех, кто хоть как-то взаимодействовал с этим чудом инженерной мысли.
Но это касается любого кода. То же самое можно сказать о коде на С#, Java или Python, кто мешает в компании где работает автор, реализовать процессы документирования и сопровождения написанного кода, передачу знаний при увольнении и поддержания нужных компетенций?!
На мой взгляд проблема в другом, разработчики просто не умеют работать с БД, не могут прочитать код хранимой процедуры. Не владеют средствами отладки. Не владеют фреймворками БД для тестирования (а они есть). То что пишет автор про структуру серверов и не возможность тестирования кроме ничего боли и сочувствия из-за не правильной организации работы не вызывает. (разработчиков хранимых процедур легко можно изолировать теми же схемами и отдельными БД в PostgreSQL, чуть ли на каждом PgConf есть пару докладов про авторазвертывание копии БД для разработчика и тестов, я не говорю уже про CI/CD где можно просто еженощно проводить сборку и тестирование, и специфичные возможности отдельных СУБД)
К сожалению такой подход работы с БД встречается все чаще и чаще и если для фронтенда эта проблема решилась выделением отдельного класса разработчиков, никто же не говорит что функции в JS не нужны, то с другой стороны (БД) такого разделения не произошло или произошло не во многих компаниях, зачастую за разработку в БД и оптимизацию запросов отвечает DBA который НЕ РАЗРАБОТЧИК, если вообще выделеный DBA есть, а это не просто DevOps/сисадмин.
Что касается миграции - да это проблема, но с другой стороны не думайте, что если Вы в своем проекте не использовали хранимые процедуры - то перейдя на другую БД у Вас все будет хорошо. На проекте с БД в несколько десятков GiB да все будет ок. Но на других размерах у Вас будут проблемы, так как в разных БД по разному реализована изоляция записи и чтения, разная стоимость блокировок и транзакций, разная стоимость привычных Вам механизмов (например, в PostgreSQL гораздо медленнее временные таблицы чем в MS SQL или Oracle). Не говоря уже о других более мелких особенностях.
В итоге разработчик действительно либо не лезет в хранимки и делает все на том что он реально умеет и понимает, либо должен владеть БД так же, как своим основным языком разработки. Разделение я думаю тут проходит от нагрузки и размера БД.
С моей точки зрения, хранимки это инструмент который имеет право на жизнь и существенно облегчает работу с БД и повышает производительность, приведу несколько примеров:
Пакетирование нескольких SQL, например, EL-T - гораздо выгоднее разработчикам пакетировать несколько SQL по осуществлению одной сложной трансформаций, чем корячится с этим в Airflow или NiFi, такой код логически скомпонован, более эффективен и легко читается, чем набор процессоров или DAG (или Python код с вызовом SQL)
Работа с временными таблицами, с учетом, что временные таблицы живут в одной сессии, а трехзвенка использует connection pooling, то гарантировать выполнение последовательных SQL и жизнь временной таблицы проще в хранимке (естественно я знаю и другие способы, но так проще)
Использование хранимых функций в запросах, например, функция дает остаток на счете на заданное время, а далее эти остатки агрегируются. Без такой логики вместо простого запроса нужно затащить всю эту логику и данные в уровень приложения и там делать агрегацию, либо писать монструозный запрос.
Упрощение сложных запросов и разбиение их на части внутри хранимки (например, для стабилизации планов запросов), при этом хранимая функция может быть источником для других запросов. Т.е. select из хранимой функции
Обеспечения единого API работы с БД если приложений работы с БД несколько, тут спорно и не микросервисно, но реализация в БД базовых примитивов, при том что с БД работает 10 разных сервисов может помочь, и я такие реализации видел
Источник хранения и тестирования технологических скриптов, выполнение специфичных БД ориентированных действий - например, создание новых партиций по расписанию, перестроение индексов и т.п. Гораздо проще прямо иметь в БД проверенные и отлаженные процедуры, чем хранить SQL скрипты где то еще и путаться в их версиях.
Автор в любом случае молодец, что поднял такую больную тему, но все же рекомендую подняться чуть выше и понять, что каждый инструмент имеет смысл и свое назначение. Если в мире автора назначения инструменту нет, то не значит, что его нет совсем.
Должен сказать, что я с вами полностью согласен.
Могу только добавить, что в очень больших компаниях держащих облако на PostgreSQL вообще нет ни хранимок, ни функций, и даже вью. Тем не менее, огромная часть бизнеса-логики живёт в SQL. И тому есть причины. Но они не имеют ничего общего с теми, которые привёл автор.
Если можно задам вопрос. Я в курсе, что у pg, если очень много временных таблиц, то распухнет pg_class. И да, это может быть проблемой. В остальном же они не пишутся в wal, а это само по себе уже высокая скорость. Соответственно, какие проблемы вы видите с временными таблицами в pg по сравнению с sql server?
Кстати, функции в read committed... надо всегда помнить, что они получают новый снимок. Как-будто, что-то не доделано было.
Основаная проблема с временными таблицами в PosgreSQL в том что это постоянное создание/удаление набора файлов, что достаточно дорого, и влияет на скорость. Скажем на том же PgConf про этот рассказывает каждый первый кто мигрует с Oracle или Ms Sql. Доходит до того, что народ делает не логируемую постоянную таблицу исполтзует ее как временнумю (заводит в ней поле с id временной сессии и асинхронной очисткой) и это бысттее.
Ну и да распухание pg_class.
Но опять же это зависит от интенствности использования, как любой инструмент требует вдумчивого применения и понимание сильных и слабых сторон.
за разработку в БД и оптимизацию запросов отвечает DBA который НЕ РАЗРАБОТЧИК
Эх, прям соль на рану. Сколько нервов , времени требуется чтобы довести эту простую мысль до разрабов и руководство их.
Абсурдная ситуация - DBA никак не участвуют в процессе разработки , но 100% как начинается промышленная эксплуатация всегда начинается - ой у нас всё медленно работает , мы уперлись в СУБД.
Угу, такое у многих болит... я был по обе стороны баррикад и в целом разрыв очень большой, а как появились ORM стал вообще огромный
ORM да , это определённый водораздел.
Я помню как всё начиналось. Какие были надежды. Как, часто бывает по жизни - идея была сделать мир лучше , а в результате в мир выпустили монстра. Они думают, что управляют чудовищем, а на самом деле чудовище управляет и полностью подчиняет себе создателя .
В результате - план запроса стоимостью триллион и вопрос разработчика к DBA - а почему он так медленно работает ? Мальчик, а на что ты надеялся с сотней джойнов, вложенными подзапросами, группировками и сортировкой ? И искреннее удивление - это не я , это ORM.
Я в другой статье уже писал такой комментарий, напишу тут тоже. Предлагаю сторонникам логики в БД провести проверку на практике. Раз вы пишете много комментариев, значит, думаю, можете и для этого найти время.
Я дам бизнес-требования, вы напишете на SQL, я на PHP, сравним код и производительность, оценим количество изменений при новых требованиях, возможности масштабирования, командной работы и автотестов.
Бизнес-требования можно найти в этой статье. Там 6 небольших действий, нужно написать веб-API, которое их делает.
Реализацию на PHP я уже написал, ссылка на репозиторий есть в статье. Можете склонировать и оставить только код контроллеров.
Так как есть готовый код, то у вас это должно занять несколько часов.
Запуск должен быть аналогичный, через docker. Внешнее поведение должно быть такое же - данные в JSON, ошибки валидации возвращаются вместе, а не по одной, сообщения об ошибках понятны пользователю. Там есть имитация запроса в стороннюю систему, ваш код тоже должен пытаться его отправить.
Я дам бизнес-требования, вы напишете на SQL, я на PHP, сравним код и производительность, оценим количество изменений при новых требованиях, возможности масштабирования, командной работы и автотестов.
А может наоборот, Вы попробуете на PHP сопоставлять пакеты их тысяч документов с десятками тысяч строк и миллиард операций в БД? В хранимой процедуре это всего один запрос, хоть и развесистый, с добрым десятком INSERT/UPDATE/DELETE/SELECT по полусотне таблиц.
Задачи бывают разные. И, в общем случае, одним ORM в обозримом будущем не обойтись.
Мое предложение сделано для проверки утверждения "Хранимые процедуры не сложнее в поддержке, чем код в приложении". Ваше предложение его ни подтвердит, ни опровергнет, поэтому нельзя сказать, что это "наоборот". Видимо вы возражаете на какое-то другое утверждение, не очень понятно на какое.
Если хотите, можем и это проверить. Делайте скрипт для заполнения базы или дамп в архиве, описание задачи и процедуру с запросом. Попробую сделать такую же логику в приложении как будет время, проверим, насколько приложение будет медленнее.
"Хранимые процедуры не сложнее в поддержке, чем код в приложении"
Как только в приложении приходится отказываться от ORM и писать SQL код, требования к разработчику и тому, кто в будущем этот код будет поддерживать, резко возрастают. А на практике, и Вы тому пример, разработчик приложения SQL если и знает, то совершенно недостаточно для оптимизации запросов. Особенно на PostgreSQL, где нет хинтов.
Если хотите, можем и это проверить. Делайте скрипт для заполнения базы или дамп в архиве, описание задачи и процедуру с запросом.
Сейчас поздно. На досуге сделаю простейшую задачу по формированию временных серий содержащих медианное время на каждую неделю с 2017 года из каждой промежуточной станции до конечной или ключевой станции на основании таблицы операций с вагонами и таблицы рейсов. Для простоты, фильтрацию оставим только срезом по q-Log-Normal 0.995
Подготовьте пока место для операций с вагонами:

Рейсы занимают на порядок меньше, не более 200 ГБ.
Во первых опыта автору явно не хватает. Не про всё темы получается экспертно рассуждать.
Во вторых статья больше похоже на хайп. Взяты всём известные выводы к которым за уши притянут свой опыт.
В третьих стройного изложения не получилось, как то хаотично изложены "мысли".
Итого - в статье раскрыты секреты Полишинеля, но уровень раскрытия ближе к уровню специалиста джуниор.
Размазанность бизнес логики в современном мире где FrontEnd , BackEnd уже архитектурно размазаны это не аргумент. И ни кого это не смущает
Простая причина не вписываться в хранимые процедуры - бедность языка самих СУБД. Например в MS SQL они не объединяются в Package,
В Oracle есть Package и даже аналоги объектов , поэтому они и Oracle Forms смогли нормально сделать.
В Postgres еще большая свобода выбора
Но у всех - обработка исключений, выстраивание структуры кода , логгирование и т.д. не дотягивают до Java хотябы.
А то что приложение может не зависеть от СУБД это миф. Вот пожалуйста 1С поддерживает 4 варианта а под капотом Postgres как предчувствие. Вычисляем процент импортозамещения в режиме Highload от 1С / Хабр (habr.com) большая разница. И приходится специальные операторы по сбору статистики вставлять для повышения производительности и еще много отклоняющегося от стандарта
Хранимые процедуры рудимент или еще актуальны?