Pull to refresh

Comments 21

UFO just landed and posted this here
Лень тут не причем. Все зависит от того, что за проект у вас.
Естественно, если у вас высоконагруженный проект с большой БД и сложной логикой запросов к БД, то Entity Framework вам не подойдет, но дело в том, что огромное количество разработчиков разрабатывает стандартные проекты с маленькими БД (до 1 млн. строк). И вот для этих проектов EF приносит кайф. Попробуйте Lynq и вы увидите какое удовольствие писать запросы в стиле lambda expression. Также никто не мешает там где это надо вызвать хранимую процедуру или обратится к СУБД на чистом SQL.
Чем помогут хранимые процедуры? На практике отказ от хранимых процедур и переход к генерации запросов, например с помощью ef, в разы увеличивает быстродействие и скорость написания.
Не могли бы вы поделиться пруфлинком по вопросу быстродействия?
Не могу, потому что результаты замеров на системах заказчика под NDA.

Но если знать немного SQL, то становится понятно, что linq-orm_ы могут построить проекцию (select) которая выбирает ровно то, что нужно для отображения. Тогда как в процедурах проекции будут широкие, ибо никто не хочет поддерживать десяток процедур.

Только эта особенность давала 20%-30% прирост в среднем на всех выборках.

А дальше для узких запросов можно удачно построить покрывающие индексы и ускорить запросы в разы.
>> Но если знать немного SQL, то становится понятно, что linq-orm_ы могут построить проекцию (select) которая выбирает ровно то, что нужно для отображения
Все это прекрасно можно сделать и на SQL.

>> Тогда как в процедурах проекции будут широкие, ибо никто не хочет поддерживать десяток процедур.
Видимо, вам просто не повезло с разработчиком БД. Понятно, что если писать плохой код, то и работать он будет плохо. Кстати, код на EF тоже надо поддерживать.

>> А дальше для узких запросов можно удачно построить покрывающие индексы
А SQL эти индексы использовать не будет?
Все это прекрасно можно сделать и на SQL.

Как например? Дублируя SQL в каждой процедуре? Или клеить строки на стороне базы?

Я вот специально посидел в трасировщике и посмотрел какие запросы генерятся. Получилось около 15 разных запросов для одной таблицы. Причем большая часть запросов незначительно отличаются предикатом и проекцией. На практике я ни разу не видел 15 процедур с минимальными отличиями для одной таблицы. Админ задолбается такое поддерживать.

Видимо, вам просто не повезло с разработчиком БД. Понятно, что если писать плохой код, то и работать он будет плохо. Кстати, код на EF тоже надо поддерживать.
Тут дело не в разработчике. Linq имеет средства декомпозиции запросов, поэтому на нем можно с помощью трех простых (точнее сказать примитивных) комбинаторов получить минимум 2^3=8 запросов.

На уровне СУБД того же самого можно добиться только склейкой строк или размножением количества процедур. И то и другое руками делать невозможно.

А SQL эти индексы использовать не будет?
Даже если будет, то менее эффективно. Потому что покрывающий индекс работает идеально когда есть проекция с теми же полями, что в индексе. Но для случая процедур никто не будет создавать десятки процедур с разными проекциями и одинаковыми предикатами, чтобы индексы работали.

А еще часто бывает, что универсальные процедуры с кучей параметров и обычные индексы не цепляют из за множества предикатов вида @p is null or fld = @p.
>> в разы увеличивает быстродействие
С этим я не могу согласиться.
T-SQL это могучая и крайне гибкая технология. Естественно, что для сложных запросов грамотно написанные хранимые процедуры будут намного более производительные, чем автоматически сгенерированный SQL код EF-ом, так как они могут в полной мере раскрыть все особенности и весь богатейший функционал СУБД MS SQL.
Мы используем EF во всех своих новых проектах, но когда сталкиваемся с действительной необходимостью оптимизации производительности, то мы используем хранимые процедуры, но на проект таких узких мест у нас на пальцах можно пересчитать.
А вот выгода в плане скорости разработки, уменьшения количества ошибок и отсутствие смены контекста между C#, Lynq и SQL, T-SQL при использовании EF приносят очень много позитивного в процесс разработки.
Естественно, что для сложных запросов грамотно написанные хранимые процедуры будут намного более производительные, чем автоматически сгенерированный SQL код EF-ом

За счет чего?

так как они могут в полной мере раскрыть все особенности и весь богатейший функционал СУБД MS SQL.

Например?

Мы используем EF во всех своих новых проектах, но когда сталкиваемся с действительной необходимостью оптимизации производительности, то мы используем хранимые процедуры, но на проект таких узких мест у нас на пальцах можно пересчитать.
Мы все еще о запросах или о массовой обработке? При необходимости сразу обновить много данных процедуры рулят. Для запросов — тормозят. EF как раз для запросов и используется.

>> За счет чего?
За счет того, что универсальное решение практически всегда проиграет по производительности специализированному. Обратите внимание на то, как автор решает «проблемы» EF? Правильно, он по сути редактирует SQL-запрос, и пытается привести его к адекватному виду.

>> Например?
Например, рекурсивные запросы.

>> Мы все еще о запросах или о массовой обработке?
Вы под запросом понимаете выборку (SELECT) данных? Если да, то о них в частности. На самом деле в наших проектах самые сложные запросы связаны именно с выборкой данных.
За счет того, что универсальное решение практически всегда проиграет по производительности специализированному.
Именно. На практике как раз процедуры делают универсальными, покрывающими много сценариев, а linq генерирует специализированные запросы с проекциями, предикатами, постраничным разбиением, которые дают гораздо больше информации оптимизатору.

Например, рекурсивные запросы.

Рекурсивные запросы помогают быстродействию? Скорее наоборот. Лучше использовать hierarchyid и вычисляемые колонки или DDC. Для деревьев крайне не рекомендовал бы использовать CTE. А для графов быстрее получается весь граф втянуть в память приложения и работать с ним, чем писать CTE.

Может быть в других базах не так, но в SQL Server я более одного раза повышал быстродействие путем отказа от CTE.
>> На практике как раз процедуры делают универсальными
Мне кажется, что вам просто не повезло с разработчиком БД. Поверьте и на EF можно писать очень плохо. Вы думаете мало тех, кто не использует проекции вообще и высасывает все данные методом ToList()? Это скорее говорит о низкой квалификации и безалаберном отношении к своей работе, чем об используемых технологиях.

>> Рекурсивные запросы помогают быстродействию?
Вы попросили пример использования особенностей MS SQL. Вот он.
Поверьте и на EF можно писать очень плохо. Вы думаете мало тех, кто не использует проекции вообще и высасывает все данные методом ToList()? Это скорее говорит о низкой квалификации и безалаберном отношении к своей работе, чем об используемых технологиях.
Я не просто верю, я регуоярно зарабатываю на проектах, где правлю такие косяки.

Но вопрос изначально был в том, что процедуры помогут сделать запросы быстрее. А пришли к тому что квалифицированный специалист с ХП сделает быстрее, чем неквалифицированный с EF. Но с таким утверждением никто и не спорил.
Вы попросили пример использования особенностей MS SQL. Вот он.

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

То есть по вашему запросы в процедурах быстрее, потому что они могут использовать CTE. На практике быстрее сделать несколько вычисляемых индексированных колонок и пользоваться EF или вообще перенести обработку на уровень приложения.
Мне кажется, что можно сформулировать и доказать следующее:
Для любого запроса, который сгенерирован генератором SQL кода, найдется такой запрос, написанный на SQL (возможно в паре с T-SQL), который не будет уступать в производительности сгенерированному.
Что думаете?

По-моему это очевидно. Проблема не в том как написать один запрос, а в том как сделать все (или те которые используются чаще всего) запросы в программе максимально быстрыми. Руками написать все такие запросы уже проблематично, а поддерживать — сущий ад. В большинстве случаев запросы будут отличаться небольшими деталями в предикатах и проекциях, а средств декомпозиции в SQL очень мало.
Вот с этим я полностью согласен.
Entity Framework отлично подходит для своих задач.
Спасибо вам за диалог.
все описанные проблемы также актуальны для EF7?
релиз EF7 ожидается в первом квартале 2016 г. Здесь можно посмотреть на некоторые новые возможности EF7:
https://github.com/aspnet/EntityFramework/wiki/Roadmap

EF7 это скорее не продолжение EF6, а переписанная чуть ли не с нуля ORM.
Вы капитан очевидность. Именно потому что она переписана чуть ли не с нуля и возник вопрос актуальности проблем, описанных статье.
В любом случае надо дождаться релиза EF 7 и проверить. Кстати, я бы не назвал описанные в статье случаи проблемами, хотя бы потому, что автор тут же в статье привел варианты их решения и почти все решения базируются на возможностях EF т. е. это скорее тонкости работы с EF, чем проблемы.
Как уже написали выше — часть описанного в статье скорее не проблемы фреймворка, а нюансы, о которых нужно знать и учитывать при написании кода. Например, все, что связано с AsNoTracking и AutoDetectChangesEnabled — справедливо и для EF7 и так и останется. Очевидно, что трекинг и определение изменений нужны во многих сценариях, и что они вносят дополнительные вычислительные расходы. Просто нужно знать, когда их можно отключить.

Проблемы с перекомпиляцией запроса для Contains, Take и Skip тоже актуальны для EF7, причем в нем пока еще нет перегруженых Take и Skip, принимающих лямбда-выражение. Т.е. на данный момент в нем все запросы, содержащие Take и Skip будут перекомпилироваться при каждом выполнении.

Насчет остального — надо проверять, причем лучше всего уже на релизной версии.

Sign up to leave a comment.

Articles

Change theme settings