Комментарии 24
Если про схему, то механизм миграций в EF — отличная вещь. Если чего-то не хватает в штатном генераторе — всегда можно дописать SQL в миграции. Если хочется отказаться от EF, то нужен отдельный скрипт под VCS, позволяющий создать/обновить базу. Хорошо, если в таком случае ведением таких скриптов будет заниматься отдельный сотрудник, который в случае чего сможет и написать скрипт под сложную миграцию базы с данными.
спасибо! всегда хотелось выработать какую-то стратегию совмещения EF с оптимизацией
хотелось бы поинтересоваться у сообщества, кто какой подход предпочитатет в плане того, какое количество логики писать на c#/linq и какое на стороне базы через хранимые процедуры/функции?
я по своему опыту предпочитаю держать слой c# максимально тонким и работать с данными через представления для чтения и хранимые процедуры для обновления. Тогда можно менять структуру базы без проблем, главное чтобы представления и процедуры не ломали контракт.
А тяжелые отчеты которые занимают время однозначно на чистом SQL через процедуры.
Хотелось бы узнать у кого какой опыт?
Делать многосоставной кластерный индекс, в котором может быть много полей — это спорный вариант для производительности, частые операции модификации могут сделать их обслуживание дорогим, а выборки начнут простаивать в блокировках ( все же таблицы достаточно большие). Фильтрованный индекс — это хорошее решение, но делать его для достаточно сложных предикатов отбора — это опять же закладывать камень под производительность. Все таки пересечения условий могут быть очень размазаны по всему возможному диапазону значений, да и содержать сложные сочетания условий and, or, is not null.
Достаточно часто встречал случаи, когда фильтруемый индекс не то, что не работал, а даже в подсказках не мог быть использован.
По ому с ним надо очень аккуратно-уж лучше секционированный индекс или по старинке разбить таблицы на оперативные и неоперативные данные.
1. RDBMS, спроектированная профессионалом
2. объекты RDBMS, написанные автором п.1
3. Максимально возможная бизнес-логика внутри п.1,2
4. Взаимодействие с БД только через п.2
5. Обертки над п.4 на процедурном ЯП и бизнес-логика, которую сложно/невозможно сделать в п.1,2
6...99999 Любые обертки и надстройки сверху п.5
Если бизнес-требования к системе более-менее устойчивы, то гораздо проще и надежнее сделать п.1,2 на T-SQL, чем пытаться извращениями добиться хотя бы порядково похожей эффективности на Linq2SQL/Linq2Entities, особенно в системах со сложной моделью данных и правилами их модификации.
Пункт 3 позволяет передавать бизнес-знания всего ОДНОМУ специалисту, и этот специалист как раз является инженером высокой квалификации.
Далее, п.4 гарантирует, что ни один джун не напишет кривой запрос, который выгрузит на клиент пол-базы, забрав в качестве payload всего один скаляр, и вообще, НЕ БУДЕТ никаких взаимодействий с БД, ни на чтение, ни на запись помимо определенных в п.2 точек входа. Мы просто запрещаем пермиссиями обращаться к данным иначе, чем через объявленные объекты (процедуры, TVF, вьюхи)
Следствием детерминирования доступа к БД является полезная возможность комбинировать средства синхронизации доступа к данным со средствами потоковой синхронизации — (например sp_getapplock). Для длинных бизнес-действий часто надежнее выстроить их в один поток этими средствами, чем использование serializable-транзакций
В п.6 и выше можно использовать специалистов любого уровня — они не смогут при всем желании ни испортить бизнес-целостность данных, ни существенно повлиять на производительность.
Где же здесь место для EF/Linq2Entities? Оно очень удобно для генерации оберточных классов вокруг сигнатур SP и резалтсетов возврата. Не более того.
Отладка такой системы очень проста — п.1,2 проверяются тест-скриптами, которые вызывают объекты БД, имитируя карту действий фронтенда. Для п.6 и выше можно использовать тестовые БД с предопределенными данными, а можно и данные, полученные прогоном тестовых скриптов из предыдущего пункта
Performance optimization делается тоже очень прозрачно — все вызовы детерминированы, а T-SQL код в них написан человеком и легко читаем/понимаем. Оптимизировать объекты БД можно прямо на лету, при условии, что сигнатуры и резалтсеты методов БД не меняются.
Имена вызываемых методов видны сразу в SQL Profiler, и обычно сразу видно что, для чего, и в каком порядке вызывается — сравните с адовой лапшой, которая льется SQL-текстом из Linq2SQL в профайлер без малейшей возможности без скрупулезного разбора понять, что именно в нем делается.
Да, тривиальный бакенд можно очень быстро накидать на code-first, но подумайте, останется ли он простым? Если концепт пойдет, не придется ли переделывать все заново? И потом, простые концепты обычно показывают бизнес-пиплу — а им нужно, чтобы было красиво. Так вот, для простых концептов дельта затрат на то, чтобы сделать T-SQL средствами модель, и обернуть ее методы EF по сравнению с code first, ничтожна относительно затрат на разработку дизайна, верстку и построение фронтенда
Linq2Entities — это отрубить себе пальцы рук, мотивируя тем, что «теперь никто не прорисовывает детали, а грубо можно и культей», затем понять, что для тонких/нестандарнтых вещей пальцы все-таки нужны — но их уже нет, и поэтому придумать 10 воркэраундов, как с гораздо меньшим успехом теперь рисовать ногами.
Руками и в частном случае можно добиться какой-то адекватной проекции второго метода на первый с точки зрения эффективности. В общем случае — нет. Поэтому для решения задач работы с данными нужно использовать именно средства работы с данными, а не обертки.
Это если еще не говорить про эффективность обработки данных «на месте». Если про нее говорить, да еще в контексте атомарности — все проблемы умножаются на порядок. Вынуть полбазы под транзакцией, модифицировать и записать назад итератором по одному — как вам такое?
И наконец, доказательство:
1. разработка программного функционала стоит денег
2. программный функционал реализует свойства системы, за счет которых она эффективно (конкурентноспособно) продается
3. только малая часть функционала RDBMS от Microsoft поддерживается в обертке их же производства — большая часть может быть использована только не-ORM средствами
4. от версии к версии количество такого не-ORM функционала, по крайней мере, не уменьшается (на самом деле — растет)
=> существует более эффективный способ работы с RDBMS, использующий весь имеющийся функционал, и поскольку объем такого функционала растет — значит, компания вкладывается в его поддержку => понимает, что без него не достичь таких показателей работы, чтобы оставаться конкурентноспособным на SMB-рынке. А поскольку, этот способ — T-SQL, это значит, что коммерчески для построения бакендов для автоматизации SMB T-SQL остается более подходящим.
А динамичные запросы вы через строки и sp_executesql делаете? В конце концов где-то что-то пропустите и вас нагнут через sql injection.Нет, конечно, так нет необходимости делать. Динамические запросы нужно строить так, чтоб никакого пользовательского ввода в код запроса просто не попадало. Это всегда можно, кроме редчайших случаев типа построения констант для некоторых вариантов полнотекстового поиска на MS SQL — вот в этих и только этих случаях да, приходится писать обертки, которые не позволят выбраться зловредному пользовательскому вводу за пределы строковых констант. Даже для запросов с 100500 вариантами фильтров, соединений и выражений в том же MS SQL, если не хотите использовать условия запуска подветок, обычно очень неплохо подходит запрос с перекомпиляцией, если вы хорошо понимаете, как написать сколь угодно большой запрос так, чтобы оптимизатор для начала гарантированно отрубил все неиспользуемые ветви, а затем эффективно построил план для оставшейся части — и да, для этого знать про option(recompile) совершенно недостаточно.
Чистый SQL не очень подходит для бизнес логики, кроме совсем простойЭто попросту не так. И да, я видел и некоторое время поучаствовал в разработке такой огромной системы. Там, совершенно как в примере gleb_l, точно такое отношение к безопасности — базовые права гарантирует сам сервер, остальное — процедурной частью, а логика вообще вся на сервере, ни одного запроса мимо интерфейсных объектов, да мимо и невозможно — см. пункт про права на объекты БД. Или же ваше утверждение требует переформулировки или дополнений, например — по факту очень трудно найти специалистов БД, которые способны все это спроектировать, расписать и при необходимости развивать и поддерживать. Например, в сравнением с рынком специалистов по C# — это очень заметно, факт.
Видите, у вас ровно обратный хрестоматийный пример — вместо разработки грамотным профессионалам — «столько «профессионалов» поучавствовало» (цитата), с предсказуемыми последствиями. Подход же, озвученный gleb_l, при условии выполнения грамотным специалистом (я понимаю, что специалистом по SQL считает себя чуть менее, чем каждый каждый первый, кто умеет написать простой запрос, но сейчас я именно про грамотных профильных специалистов) очень устойчив при использовании разношерстной командой, уже в одном этом его огромный плюс.код бакенда разрабатывается одним профессионаломУ меня как раз система с горами такого. Спасибо, за двадцать лет там столько «профессионалов» поучавствовало, что волосы встают дыбом, там где их и быть-то не должно.
Чистый SQL не очень подходит для бизнес логики, кроме совсем простой. Можно конечно через SQL CLR делать, но тоже так себе удовольствие. На Оракле конечно повеселее, а для SQL server-а это занятие для не слабых духомЭто говорит лишь о том, что с Ораклом вы сколько успели проработать, а с MSSQL — нет. Тут все дело в том, что подходы к ним очень, очень разные. При переходе от одного к другому — неважно, в каком порядке — сначала необходимо полностью перестроить мозги, сломать привычное мышление, совершенно изменить подход. Начинать писать на t/sql и обнаружить, что в нем отсутствуют привычные так необходимые объекты и пайпланы или, наоборот, перейти на Оракл и обескураженно искать, где же тут локальные времянки, без которых жизнь как без воздуха, и непосредственная отдача резалтсета из процедурной части клиенту — поначалу просто апатия, проклятия и ненависть, без преувеличения. Холивары MS SQL vs Oracle потому так и унылы и однообразны, что читаешь аргументы что одной, что другой строны — и видишь только, что аргументаторы привыкли мыслить только одной парадигмой, а противоположная обеим сторонам кажется какой-то инопланетной дикостью, поэтому эффективно мыслить за обе стороны мало кто пытается. В действительности же и у той, и другой стороны есть свои сильные и слабые стороны, опять же хрестоматийный случай.
Ну и да, никто обходиться без CLR не заставляет, даже совершенно не для написания на нем бизнес-логики, а исключительно для базовых вещей, которые почему-то до сих пор не завезли в MS SQL, например, почему-то отсутствующего инструментария для использования регулярок, из-за чего у каждого разработчика есть своя библиотечка на этом CLR для оберток над функционалом для работы с ними. Видите, я использовал аргумент из первой десятки в пользу Оракла, где регулярки давно из коробки :)
Практически все эти детские болезни мы полечили в linq2db. Клеить строки не надо, Dapper не надо, делать хранимки на каждый чих не надо.
- Хинты можно использовать
- CTE из каробки, вместе с рекурсивными CTE
- Union, Concat собирает все что надо, хоть завались ими
- INSERT FROM, INSERT INTO, UPDATE FROM...
- Менять названия таблиц налету
- Использовать временные таблицы
- Оконные функции из каробки
- BulkCopy на все поддерживаемые базы данных
- CRUD по CQRS паттерну, ничего лишнего вплоть до единственного поля
- ...
“Но они продолжали жевать кактус и дискутировать какой generic repository лучше и когда стартовать UoW.”
github.com/linq2db/linq2db.EntityFrameworkCore
Методы оптимизации LINQ-запросов в C#.NET