Ленивый читает в замке.ActiveRecord
-
19-08-2019 - |
Вопрос
Я пишу приложение, которое должно периодически (например, каждую неделю) перебирать несколько миллионов записей в базе данных и выполнять код для результатов каждой строки.
Поскольку таблица такая большая, я подозреваю, что когда я вызываю SomeObject.FindAll (), она читает все 1,4 миллиона строк и пытается вернуть все строки в SomeObject [].
Есть ли способ, которым я могу выполнить выражение SomeObject.FindAll (), но загрузить значения более удобным для СУБД способом?
Решение
Не с FindAll()
- который, как вы и предполагали, будет пытаться загрузить все экземпляры указанного типа за один раз (и, в зависимости от того, как у вас настроен NHibernate, может выдать огромное количество SQL-запросы для этого).
Ленивая загрузка работает только со свойствами объектов, например, если у вас был постоянный тип SomeObjectContainer
, у которого в качестве свойства был список SomeObject
, сопоставленный таким образом, что он должен соответствовать всем lazy="true"
и с помощью foreach
, затем добавив <=> к этому свойству списка, вы получите то, что хотите, в некотором роде; по умолчанию NHibernate будет выдавать запрос для каждого элемента в списке, загружая только по одному за раз. Конечно, кэш чтения может вырасти, поэтому вам, вероятно, придется много сбрасывать.
Что вы можете сделать - это выполнить запрос HQL (или даже встроенный SQL), чтобы получить все идентификаторы для всех объектов SomeObject, а затем выполнить циклический просмотр идентификаторов по одному за раз, выбирая соответствующий объект с помощью FindByPrimaryKey. Опять же, это не особенно элегантно.
Честно говоря, в такой ситуации я бы, вероятно, превратил это в запланированное задание обслуживания в хранимом процессе - если только вам действительно не нужно запускать code для объекта, а не манипулировать данными как-то. Это может раздражать пуристов объектов, но иногда сохраненный процесс - это правильный путь, особенно в сценарии пакетного задания такого типа.