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

T-SQL в .NET Core EF Core: Гибридный подход к производительности и гибкости (Переосмысление с учетом обсуждения)

Уровень сложностиСредний
Время на прочтение11 мин
Количество просмотров3.7K
Всего голосов 2: ↑0 и ↓2-2
Комментарии20

Комментарии 20

Как разрботчик баз данных с многолетним опытом скажу: за всё время работы на проектах могу смело утверждать, что единственное взаимодействие с данными, того же c#, должно быть исключительно через хранимые процедуры или функции. Будь то простой SELECT или сложная аналитика данных. Нет ниодного серьезного аргумента, обработки данных, написания кода SQL вне DB. Единственный код который пишет разработчик бэка для взаимодействия с данными - это вызов хранимых процедур и функций. Точка. Остальное от лукавого и в конечном итоге рано или поздно вылезет проблемами

Где вот та магическая линия разграничения, которая разделяет обработку данных и интеграцию бизнес логики в хранимки?

Нет ниодного серьезного аргумента, обработки данных, написания кода SQL вне DB.

  1. Это проще, достаточно знать только C# что бы писать сложные запросы.

  2. Это позволяет писать один код, для всех баз для которых есть linq провайдер.

  3. Код на C# легче отлаживать и тестировать.

  4. Развертывание обычно проще

Это позволяет писать один код, для всех баз для которых есть linq провайдер.

Только в случае чего-то лёгкого, а когда начинаются оптимизации и хинты на высокой загрузке: rowlock, nolock, merge и т.п., то универсальность linq уходит за фасад, завод или в те самые хранимки.

Это уже не хинты, а костыли. Очень странно выдавать грязное чтение как оптимизацию. да в причинах rowlock merge надо разбиратся - смотреть схему, запросы, профиль нагрузки.

Это уже риторика, давайте обойдёмся без абстракий.

Как в руках квалифицированного админа root права дают огромнейшее поле для оптимизаций, так и в руках админа БД использование существующих инструментов даёт качественный инструмент.

Или не даёт, а ведёт к аккуратно разложенным багам и прибитыми гвоздями планам запросов.

Да, понимаю. Когда есть убеждённость в одном инструменте, все другие инструменты воспринимаются предвзято.

И я полностью Вам понимаю, у меня такое-же предвзятое отношение к jQuery и AutoMapper. Ничего не могу с собой поделать, просто не люболю их.

Извините, я не до конца понял, Вы за код SQL внутри БД или против?

Я как разработчик который пользовался типизированными датасетами, писавший свой ORM для .NET Framework 2.0, использовавший Linq to SQL, Entity Framework, писавший хранимки и видел проекты где логику пихают в хранимки, могу сказать что каждый инструмент подходит для свой задачи.

Главное не переусердствовать и не отказываться от другого по необоснованной предвзятости.

Сразу видно здоровое зрелое видение и мнение. Согласен.

Радикальный подход. Хотя, конечно, имеет право на существование. А как Вы сочетаете с ORM (EF в частности)? На мой взгляд для простых атомарных операций и небольших выборок CRUD все же довольно удобно использовать LINQ.

Можно попробовать всю бизнес логику агрегатов написать на хранимых процедурах и вероятнее будет работать. Есть агрегат, необходимо выполнить команду для перевода его из состояния А в состояние Б, проверить возможность перехода, валидацию входных данных и тд. Возможно ли это на хранимых процедурах? В принципе да . Но лучшее ли это решение? Есть куда более продвинутые языки, чем SQL, которые более элегантно и лаконично решат такую задачу. Помимо всего прочего, я плохо себе представляю юнит тестирование хранимых процедур. Как там с фреймворками для тестирования как там с расчетом кавереджа? Рискну предположить, что никак.

Так что по идее обработку command лучше делать на каком-то logic-driven языке типа C#. Там тебе и ООП, где-то с оттенками функциональщины и АОП. А вот query по натуре data-driven и их реализовывать на вьюхах и хранимках как будто самое то. Query абстрагировать от хранилища данных и их типа невозможно.

Далее для оркестрации условного веб приложения вам все равно нужен язык, который умеет делать http запросы в сеть, умеет работать с брокерами сообщений и тд.

В целом гибрид это всегда путь, к результату можно придти и по нему.

Спасибо за Ваш комментарий.

Вы верно выбрали пример агрегата. Да, бизнес логику можно сделать на T-SQL. Да, это другой образ мышления и парадигма, прямого аналога юнит-тестированию я не подскажу. Но мой личный опыт показывает, что да, тестирование кода конечно производится по ходу разработки. В итоге, если все сделано грамотно, работает очень надежно годами, если не десятилетиями. В SQL существует достаточно развитая типизация данных. Есть TRY..CATCH... Обычно решения получаются железобетонные. Да могут появиться в работе какие-то сбои, но все это внутри сервера довольно хорошо диагностируется, находится и исправляется, если на первоначальном этапе закралась ошибка. Конечно все зависит от квалификации разработчика и степени его осознания, что он творит и в какой предметной области.

Заканчивая ответ на Ваш вопрос, главное преимущество и наиболее заметная разница наступает в случае массовой обработки агрегатов (как одно действие). Например несколько тысяч. Решение на C# и EF будет работать точно медленнее и возможно на пару порядков раз.

Еще раз подчеркиваю, сравнивать надо между C# LINQ и T-SQL при достаточно квалифицированном подходе в каждой области. T-SQL предоставляет множество возможностей, о которых не глубокие специалисты не имеют представления.

Кроме вышеописанного примера, наверное одно из основных преимуществ SQL в том, что на нем проще писать код с мгновенной проверкой на соответствие со сложными структурами данных, по ходу разработки. Что просто позволяет намного быстрее находить нужные решения. Когда все процедуры и их параметры определены, их легко инкапсулировать и вызывать через SQL, LINQ, EF из C# приложений. На мой взгляд это также на порядки быстрее и проще, т.к. существенно меньше накладных расходов и посредников в виде ненужной разработки промежуточной системы классов, методов и т.д...

В этом суть ориентации на подход Data-Driven Design. На T-SQL, в принципе, можно сделать всё.

Важное замечание. В ряде случаев, при этом, работа с данными необходима через ООП и ORM, обычно для пользовательских интерфейсов и обработки единичных экземпляров агрегатов. Хотя ORM может быть очень легковесным при этом, т.к. любая логика может быть на SQL.

В целом выглядит интересно. Я бы посмотрел на проект, реализованный таким образом.

Но есть одно ограничение, насколько я знаю такое невозможно сделать на всяких key/value базах вроде DynamoDB. Ну вроде как ещё Mongo поддерживает хранимые процедуры. Можно и в Redis такое добавлять на lua.

И тут сразу приходит в голову завязка бизнес логики на движок данных. Т.е. условно в процессе разработки и жизнедеятельности приложения выясняется, что наилучшим решением будет другой движок. И теперь задача на только мигрировать данные в другой движок (с час справляются инструменты вроде Debezium), но ещё и как-то перенести логику. С другой стороны логику query в любом случае придется переписывать. А с третьей стороны логика query чаще всего менее критична, чем логика command.

В общем тут есть над чем подумать.

Тема только для тех у кого MSSQL уже является неотъемлемой частью корпоративной ИТ-инфраструктуры. Или не корпоративной.

Берем LinqToDB.EntityFrameworkCore и вытираем все пункты почему мы не можем использовать LINQ, включая CTE, хинты и плохо сгенерированный SQL. Да и не в LINQ дело, а в LINQ провайдере, коим является EF Core.

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

Для меня преимущества использования хранимых процедур и функций состоят из:

  1. Возможности более тщательной оптимизации запросов

  2. Относительно быстром процессе прототипирования, потому что мы, по сути, напрямую манипулируем данными

  3. Упрощенный процесс доставки. Ведь правда, мы просто загрузили новый код в БД и он становится сразу доступен конечному пользователю

Но как мне кажется, по крайней мере 2 из 3 пунктов (кроме первого) относятся только к ранним стадиям разработки. Как по мне, применение SQL в качестве языка выражения бизнес-требований - тупиковый путь, он просто никуда не ведет и заставляет систему стагнировать и не дает ей полноценно развиваться:

  • Мы сильно привязываемся к одному решению по хранению данных (что в контексте SQL Server и текущей обстановки становится еще критичнее). Плюс, горизонтальное масштабирование при использовании такого подхода представляется весьма болезненным. А если мы решим перейти на другое решение, особенно, на NoSQL ввиду новых бизнес-требований? Перенос одних только данных может потребовать немало усилий, а тут еще переписывать логику придется.

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

  • Стоит учитывать также проблему поиска сотрудников, которые как минимум смогут, а как максимум хотя бы захотят работать с такой системой. Из-за сильной связанности инфраструктурных деталей и бизнес-логики разобрать процедуру, длина которой составляет хотя бы 50-100 строк становится очень проблемно, и процесс погружения нового человека в это весьма сложен.

Впрочем, очевидно, что в критически важных по производительности участках системы эффективнее напрямую писать запросы SQL или же использовать процедуры и функции, например, для сбора аналитических данных для отчетов.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации