2010-01-25 2 views
1

Мы используем NHibernate для ORM, и на этапе инициализации нашей программы нам нужно загрузить много экземпляров некоторого класса T из БД.Консолидация открытых сессий NHibernate в DB (связь NHibernate и DB)

В нашем приложении, следующий код, который извлекает все эти случаи, принимает навсегда:

public IList<T> GetAllWithoutTransaction() 
{ 
    using (ISession session = GetSession()) 
    { 
     IList<T> entities = session 
      .CreateCriteria(typeof(T)) 
      .List<T>(); 
     return entities; 
     } 
    } 
} 

Используя NHibernate журнала я обнаружил, что фактический SQL запросов каркасных использования являются:

{ 
    Load a bunch of rows from a few tables in the DB (one SELECT statement). 

    for each instance of class T 
    { 
     Load all the data for this instance of class T from the abovementioned rows 
     (3 SELECT statements). 
    } 
} 

3 оператора выбора связаны, то есть вторая зависит от первой, а третья - от первых двух. Как вы можете видеть, количество операторов SELECT составляет миллионы, что дает нам огромные накладные расходы, которые возникают непосредственно из всех этих вызовов в БД (каждый из которых влечет за собой «открытый сеанс БД», «закрыть сеанс БД», .. .), хотя мы используем один сеанс NHibernate.

Мой вопрос: Я хотел бы как-то объединить все эти операторы SELECT в один большой оператор SELECT. Мы не запускаем многопоточность и никоим образом не изменяем БД на этапе инициализации.

Одним из способов сделать это будет определение моего собственного объекта и его отображение с помощью NHibernate, которое будет загружено быстро и загрузится все в одном запросе, но для этого потребуется, чтобы мы выполняли операции соединения, используемые в этих утверждениях сами, и хуже - ломает абстракцию ORM. Есть ли способ сделать это с помощью некоторой конфигурации?

Спасибо, ребята!

+0

Вы пробовали играть с размером партии? – hackerhasid

+0

Если вы действительно новичок в NHibernate, вы можете взглянуть на профайлер nhibernate. – Min

+0

NHibernate не предназначен для пакетной обработки. Я использую NHibernate для 99% запросов, но для пакетной обработки ETL или простой sql могут работать лучше. – Paco

ответ

3

Это называется SELECT N+1 problem. Вам нужно решить, где вы собираетесь размещать свои соединения (FetchMode.Eager)

0

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

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

Существует много хорошей информации об этом в документах NHibernate. Вы можете начать здесь:

http://www.nhforge.org/doc/nh/en/index.html#performance-fetching

+0

Спасибо, ребята! У меня пока нет решения, но я пойду к решению в направлении ответа Маурисио. Я сообщу, когда доберусь туда. –

+0

Наконец-то мне удалось настроить NHibernate на загрузку всего в одном запросе, используя fetch = "join" и все такое. Основная проблема заключалась в том, что у меня были круговые зависимости, у класса T был список экземпляров типа T, и мне нужно было определить промежуточное отображение для его работы. Еще раз спасибо за вашу помощь! –

Смежные вопросы