Следует ли вам отказаться от инфраструктуры ORM, когда вам нужно реализовать массовую операцию?

15

Вот обычная ситуация:

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

Вот мой вопрос:

  • В этой ситуации, вы должны предпочесть решение, которое включает в себя сырой SQL?
  • Или есть хорошо известные шаблоны проектирования, которые могут помочь вам решить проблемы, которые обычно связаны с массовыми операциями в рамках ORM?

РЕДАКТИРОВАТЬ:

  • Я не спрашиваю, следует ли вам удалить структуру ORM из всего приложения.
  • Я спрашиваю: должны ли вы отказаться от платформы ORM для этого небольшого фрагмента приложения?
Джим Г.
источник
Я не знаю, стоит ли вам что-то делать, но вы пытались дозировать свою массовую операцию?
ChrisAnnODell

Ответы:

13

ORM не предназначены для полного доступа к вашей базе данных. Используйте их для 80% кода, который является CRUD, слишком трудоемким, чтобы писать его самостоятельно. Используйте хранимые процедуры, динамический SQL или все, что вы хотите, за оставшиеся 20%, которые необходимо тщательно оптимизировать.

Роберт Харви
источник
4
Это сработало бы, если бы абстракция базы данных не была одной из основных причин, по которой вы решили использовать ORM.
@ Pierre303, мне трудно понять твой комментарий. Что вы имеете в виду?
Марк Канлас
@MarkCanlas: я думаю, что он имеет в виду «абстрагирование базы данных» в том смысле, что вы можете изменить базу данных (например, перейти с SQL Server на MySQL), если вы хотите это сделать. На практике этот вариант использования практически не встречается.
Роберт Харви
1
Вы все еще можете создавать абстракции. Большинство ORM, которые фактически поддерживают несколько провайдеров / диалектов, поддерживают код, специфичный для провайдера / диалекта. Вы можете реализовать операции как массовую вставку / привязку массива / TVP / что угодно для определенных баз данных и позволить им переключаться на медленный за медленным для неподдерживаемых провайдеров, таких как SQLite. В худшем случае вы можете разбить функциональные возможности, которые могут быть массовыми, на отдельный интерфейс / класс и подпрограмму в другой реализации, основанной на параметрах сборки или конфигурации.
Ааронаут
Да, могут помочь пользовательские диалекты, а также конкретный код для конкретных задач. Однако, чтобы это было жизнеспособным с финансовой точки зрения, это должно быть ограничено строгим минимумом. Наши настраиваемые пользовательские функции (диалекты) составляют менее 0,1% от общей базы кода доступа к данным. Я был бы очень обеспокоен, если бы это было больше, чем это.
7

Я использую ORM (nHibernate) в приложении, которое требует высокой производительности и обрабатывает миллиарды записей. Со временем мы заметили, что наиболее серьезные проблемы с производительностью были связаны с нашим собственным способом использования ORM, а не с одним ORM.

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

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

  • Мы использовали профилировщик ORM. (мы использовали nhprof)
  • Мы использовали профилировщик базы данных. (мы использовали SQL Server Profiler)
  • Мы прочитали как можно больше статей на эту тему. (Многие были доступны для nHibernate в дополнение ко всей главе по теме в документации)
  • Мы купили конкретные книги по производительности и масштабируемости.
  • Мы создали систему бенчмаркинга для проверки наших собственных оптимизаций.
  • и что еще более важно, мы смогли протестировать наш код на реальных клиентах с огромными данными. Одна только эта последняя вещь помогла нам обнаружить большинство проблем в нашем приложении.
Дэн МакГрат
источник
1

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

TMN
источник
1

ОРМ не делают ничего волшебного. Они переводят методы доступа к объектам в SQL. Операторы SQL, которые они выполняют, не обязательно медленнее, чем SQL, который вы пишете вручную. Сказав это, есть несколько вопросов, на которые вы можете наткнуться:

  1. Транзакции: одна большая массовая операция почти всегда быстрее, чем многие маленькие транзакции, которые вместе выполняют одно и то же. Следовательно, если в вызовах методов ORM используются мелкозернистые транзакции (например, активные методы стиля записи в сущностях Spring Roo помечаются как @Transactional), массовые операции будут медленными. Если это так в вашем приложении, вы должны взглянуть на логику транзакции.
  2. Кэширование: в Hibernate кэш первого уровня позволяет вашему менеджеру объектов избегать ненужных обращений к базе данных. В целом это хорошо, но плохо для массовых вставок, где это приводит к ненужному засорению кэша, что приводит к снижению производительности приложения. Если это ваша проблема, вы должны взглянуть на шаблон Batching, предложенный выше ChrisAnnODell. Мы используем его в наших импортерах, и это значительно ускоряет массовые вставки.

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

Валленборн
источник
Чтобы избежать кеша, используйте StatelessSession. Также избегайте идентификаторов автоинкремента. Вместо этого следует использовать HiLo или Guid.
1

Обойти ORM. Не только это, но и обходить "обычный" sql. Используйте массовую утилиту вашей базы данных, чтобы вставить очень большие наборы данных в промежуточную таблицу. Затем используйте sql для выполнения ваших действий.

Ваш ORM "изюминка блога" может работать не во всех ситуациях.

Лорд тидус
источник
Правильно, такие бэкэнд-инструменты доставляют много хлопот, но через 3-4 раза вы станете экспертом и сможете делать что-то быстрее, а иногда и иначе. Это как разница между лопатой и бульдозером. Я написал инструменты, контролируемые сценариями, для различных платформ, чтобы читать файлы ввода текста и обновлять данные с помощью низкоуровневых операций. Написание такого инструмента также может сделать вашу жизнь проще (или, по крайней мере, более интересной). Подобные вещи можно использовать для настройки данных настройки клиентских установок во время обновлений программного обеспечения.
0

Был в такой ситуации. Иногда приходится.

Некоторые ORM позволяют разработчику пропускать объектную модель и переходить прямо к уровню базы данных.

Есть также ORM, которые используют массовые операции, инкапсулированные, как объектно-ориентированные.

umlcat
источник
0

Как упоминалось umlcat , есть несколько ORM, которые позволят вам использовать массовые операции.

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

Это также облегчает модульное тестирование и отладку. Если у вас есть хорошее тестовое покрытие для ваших методов ORM, вы можете использовать его в своих приложениях. В противном случае отладка необработанного SQL (особенно большого с транзакциями и множеством JOIN) может стать проблемой.

Однажды мне потребовался почти день, чтобы обнаружить ошибку в необработанном вызове SQL, которая была почти 100 LOC, и ошибка была просто одним символом! С тех пор я стараюсь избегать использования необработанного SQL в приложении, а все процедуры SQL проверяются отдельно.

Аттила О.
источник
0

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

Pieter
источник