ORM vs. Хранимые процедуры

png vs jpegМой коллега, позавчера в очередной раз у себя в блоге поднял этот больной вопрос.

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

Хранимые процедуры

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

  1. Хранимые процедуры компилируются и за счет этого исполняются быстрее, чем обычные SQL скрипты (как написанные вручную, так и сгенерированные ORM).

  2. Если вам необходимо обработать много данных и вернуть мало результатов, то без хранимых процедур вам не обойтись.

Я не буду спорить с этими достоинствами, т.к. я с ними полностью согласен.

Но практически все защитники подхода с хранимыми процедурами молчат о недостатках:

  1. RDBMS не выполняют контроль целостности кода хранимой процедуры при изменении схемы данных, от которых хранимая процедура зависит.

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

    Чтобы не быть голословным приведу пример (MS SQL Server):

    1. тестовый скрипт.

    2. вывод в консоль.

    Обратите внимание, что процедура sp_rename только предупреждает, что что-то может сломаться, но не говорит что именно. А если я просто вручную удалю колонку? Я об этом никогда не узнаю.

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

  2. Хранимые процедуры отделены от клиентского кода, который их вызывает.

    Если хранимая процедура была удалена, или переименована, или просто изменились её параметры об ошибках я узнаю только в момент попытки ее выполнения. Обычно хранимые процедуры используются в качестве средства устранения дублирования кода и, как следствие, вызываются разными клиентами. Т.е. в дополнение ко всем связям между объектами мне необходимо держать в голове информацию о всех клиентах и всех хранимых процедурах, которых они вызывают. В общем случае это ведет к тем же последствиям, что и в пункте 1.

    Для того, чтобы посмотреть как ведет себя хранимая процедура, ее код, найти подходящую процедуру и т.п. мне необходимо открыть IDE для моей любимой RDBMS. Т.е. переключить контекст своего внимания. Иногда, когда я таким образом отвлекаюсь я очень долго не могу вернуться к работе.

  3. Хранимые процедуры не переносимы между различными типами RDBMS.

    Вы конечно можете сказать, что это чушь и, от части, будете правы, но только в том случае если вы делает корпоративный или уникальный продукт под заказ.

    Но, очень часто продуктовые компании, разрабатывающие коробочные или близкие к ним кастомизируемые тиражируемые решения, попадают в зависимость от требования клиента: “Ваш продукт хорош, но он использует Oracle, а мы используем MS SQL и хотелось бы….” В этом случае есть 2,5 возможных развития сюжета: вы говорите, что это не возможно и теряете клиента; вы говорите, что нужно подождать полгода (год, два, …) и клиент уходит; или остается и вы судорожно начинаете искать специалиста по MS SQL, переписывать ваши хранимые процедуры и так далее.

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

ORM

"Минусы" ORM:

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

    К примеру NHibernate, которую я считаю лучшей, предоставляет следующие возможности для написания запросов:

    1. LINQ - самый высокоуровневый объектный подход к написанию запросов.
    2. CriteriaAPI или QueryOver - объектный, но SQL-ориентированный подход.
    3. HQL - hibernate query language - SQL-подобный язык для написания запросов.
    4. SQL - “голый” SQL
    5. Хранимые процедуры.

    Также могу сказать, что кривость и неоптимальность запроса почти всегда напрямую зависит от кривости рук разработчика.

  2. ORM тратит время на трансляцию запросов в SQL Да, но: это время не такое уж и большое; большинство ORM транслирует запрос в SQL только при первом выполнении запроса, затем они его кэшируют.

  3. ORM - большие страшные монстры, для маленьких проектов, как “из пушки по воробьям”

    На это могу возразить то, что существует множество мелких ORM. Так же можно использовать ORM напрямую и не заботится ни о каких DDD и прочих монструозных технологиях. К примеру, использование NHibernate + FluentNHibernate (автомаппинг) требует от разработчика написания 2х классов: 1. Конифигурацию NH; 2. Конфигурацию автомапинга. Причем эти классы могут быть практически без изменения кочевать из проекта в проект.

Плюсы ORM для меня (в порядке появления в голове):

  1. ORM обеспечивает контроль целостности схемы данных

  2. ОРМ позволяет работать с данными как с объектами. При этом обеспечивается контроль типов.

  3. Некоторые ORM (EF, LLBLGen Pro) позволяют генерировать строго-типизированные обвертки, для вызова хранимых процедур.

  4. Мне не нужно писать никакого кода на страшном ADO.NET.

  5. Большинство ORM поддерживает несколько типов баз данных.

Применительно к NHibernate:

  1. NHibernate поддерживает группировку запросов в пакеты и таким образом уменьшается количество обращений к RDBMS

  2. NHibernate поддерживает отложенные запросы, которые выполнятся только в момент первого обращения к результатам. При этом все отложенные невыполненные запросы выполнятся в одном пакете.

  3. Second Level Cache - очень мощный инструмент. В умелых руках, повышает производительность приложения в разы.

Заключение

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

Если в вашем проекте требуется мощь хранимых процедур, или скриптов написанных на SQL, то всегда используйте их вместе с, а не вместо ORM. Также я рекомендую пользоваться хранимыми процедурами только в исключительных ситуациях: только тогда, когда без них не обойтись.

comments powered by Disqus