Недостатки объектно-реляционного отображения - PullRequest
6 голосов
/ 07 сентября 2011

Я фанат ORM - Object Relational Mapping, и я использую его с Rails последние полтора года. До этого я использую необработанные запросы с использованием JDBC и заставляю базу данных выполнять тяжелую работу через хранимые процедуры. С ORM я был изначально счастлив делать такие вещи, как coach.manager и manager.coaches, которые были очень простыми и легко читаемыми.

Но с течением времени появлялись многочисленные ассоциации, и я заканчивал тем, что делал a.b.c.d, которые запускали запросы во всех направлениях, за кулисами. С рельсами и рубином сборщик мусора сошел с ума и занял безумное время, чтобы загрузить очень сложную страницу, которая содержит относительно меньше данных. Мне пришлось заменить этот код в стиле ORM простой хранимой процедурой, и результат, который я увидел, был огромен. Страница, загрузка которой заняла 50 секунд, теперь занимает всего 2 секунды.

С такой огромной разницей я должен продолжать использовать ORM? Совершенно очевидно, что он имеет серьезные накладные расходы по сравнению с необработанным запросом.

В целом, каковы основные подводные камни использования среды ORM, такой как Hibernate, ActiveRecord?

Ответы [ 6 ]

12 голосов
/ 07 сентября 2011

ORM - это всего лишь инструмент.Если вы не используете его правильно, у вас будут плохие результаты.

Ничто не мешает вам использовать выделенные запросы HQL / критериев, с выборочными соединениями или проекциями, чтобы возвращать информацию, которую ваша страница должна отображать в минимально возможном количестве запросов.Это займет более или менее то же время, что и выделенные запросы SQL.

Но, конечно, если вы просто получите все по идентификатору и перемещаетесь по своим объектам, не осознавая, сколько запросов оно генерирует, это приведет к длительному времени загрузки.Ключ должен точно знать, что ORM делает за сценой, и решить, является ли это уместным или должна быть принята другая стратегия.

5 голосов
/ 07 сентября 2011

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

Как вы заметили, обход нескольких отношений, таких как a.b.c.d, может быть неэффективным, потому что большинство программ ORM будет выполнять независимый запрос к базе данных для каждого . по пути.Но я не уверен, что это означает, что вы должны полностью исключить ORM.Большинство решений ORM (или, по крайней мере, конечно, Hibernate) позволяют вам задавать пользовательские запросы, где вы можете вернуть именно то, что вы хотите в одной операции базы данных.Это должно быть примерно так же быстро, как ваш выделенный SQL.

На самом деле проблема в том, чтобы понять, как слой ORM работает за кулисами, и понять, что хотя что-то наподобие a.b.c.d просто написать, то, что заставляет слой ORM делать, когда он оценивается, не,Как правило, я всегда начинаю с самого простого подхода, а затем пишу оптимизированные запросы в тех областях, где это имеет смысл / где очевидно, что простой подход не масштабируется.

3 голосов
/ 07 сентября 2011

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

Например, для операций CRUD среды ORM, такие как Hibernate, могут ускорить разработку и будут работать достаточно хорошо.Иногда вам нужно сделать некоторые необходимые настройки для достижения приемлемой производительности.Я не уверен, что ваша задача (что заняло 50 секунд в Hibernate) не может быть выполнена правильно с Hibernate, потому что вы не предоставили нам детали.

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

2 голосов
/ 07 сентября 2011

Как уже упоминалось, ORM - это всего лишь инструмент, и вы можете использовать его хорошо или плохо.

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

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

1 голос
/ 07 сентября 2011

Я с Петаром из твоих комментариев по поводу ленивого извлечения.Допустим, у вас есть html-таблица, заполненная полями из объекта abcd. Вы могли бы найти ваш фреймворк для обхода базы данных тысячи раз (возможно, намного больше).Недостатком ORM в этом случае является необходимость внимательно читать документацию.Большинство фреймворков поддерживают отключение отложенной выборки, а многие даже поддерживают добавление собственной логики обработки для связывания набора данных.

Суть в том, что почти любой ORM почти несомненно лучше, чем все, что вы собираетесь написать самостоятельно.Вы будете обременены поддержкой огромных стандартных библиотек или, что еще хуже, будете писать один и тот же код снова и снова.

0 голосов
/ 12 мая 2013

В настоящее время мы изучаем возможность перехода с нашего собственного уровня хранилища данных с четким разделением объектов переноса и объектов доступа к данным в JPA.Мы использовали генератор для создания TO, DAO и SQL DDL, а также из некоторой документации в формате docbook.Благодаря этому все наши материалы из документации, структуры базы данных и сгенерированных классов Java всегда синхронизированы с хорошей документацией самой базы данных.

Что мы обнаружили до сих пор с помощью JPA:

  1. Ссылки на внешние ключи нельзя использовать для импорта, некоторых специальных запросов и т. Д., Поскольку их нельзя размещать в управляемом объекте.JPA допускает только целевой класс там.
  2. Доступ к некоторой области пользовательского сеанса затруднен до невозможности.Мы до сих пор не знаем, как получить идентификатор пользователя в столбце «userWhoLastMadeAnUpdate» в каком-либо методе PrePersist.
  3. Что-то, что ожидается с помощью ORM, будет довольно простым, а именно «отображение классов» вообще не работает.Мы используем HalDateTime (http://sourceforge.net/projects/haldatetime/) для внутреннего использования. Особенно в клиенте. Сопоставление его с JPA напрямую невозможно, хотя HalDateTime поддерживает его. Из-за ограничений JPA нам необходимо использовать два поля в сущности.
  4. JPA использует либо один XML-файл для описания сопоставления, поэтому вам нужно рассмотреть как минимум два файла, чтобы понять взаимосвязь между классом Java и базой данных. И XML-файл становится огромным для больших приложений.
  5. В качестве альтернативы ORM предоставляют аннотации в самом классе Java, поэтому их легче изучать и понимать взаимосвязь, но это заставляет вас видеть все эти элементы базы данных на уровне клиента (что полностью нарушает надлежащий уровень).
  6. Вам придется ограничиться тем, чтобы оставаться как можно ближе к чистой структуре базы данных, иначе вы наверняка получите кучу запросов и заявлений со стороны ORM.
  7. Используйте ORM, который предоставляет запросязык, близкий к самому SQL (см. JPAмс вполне приемлемо здесь).Использование ORM-языка делает поддержку больших приложений очень дорогой.
...