2012-03-30 14 views
13

Chcę przyspieszyć operacje masowe insert przy pomocy NHibernate 3.2 na Oracle 11g. Aby to zrobić, próbowałemPrzyspieszenie operacji wstawiania zbiorczego za pomocą NHibernate

Session.Save(entity); 
Session.Flush(); 
Session.Clear(); 

... w moim foreach pętli ale dostał wyjątek wyrządzone przez obiekty brakujących w sesji:

udało się leniwie zainicjować kolekcję rola MyClass.PropertyX, no sesji lub sesja została zamknięta

Kolejną próbą było ustawić wielkość wsadu:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> 
    <session-factory> 
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> 
    <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property> 
    <property name="connection.connection_string">xxx</property> 
    <property name="dialect">NHibernate.Dialect.Oracle10gDialect</property> 
    <property name="adonet.batch_size">50</property> 
    <property name="query.substitutions">true=1, false=0</property> 
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property> 
    </session-factory> 
</hibernate-configuration> 

dodatkowo ustawić Session.SetBatchSize(50) w moim kodu uzyskałem następujący wyjątek:

Nie wielkość partii został zdefiniowany dla fabryki sesji, Składowanie jest wyłączone. Ustaw adonet.batch_size = 1, aby włączyć grupowanie.

Jedynym miejscem, w którym ten wyjątek został zgłoszony, jest NonBatchingBatcher, więc wygląda na to, że moja sesja ma nieprawidłowy batcher.

Co jest nie tak? Jak mogę przyspieszyć wstawianie wsadowe z NHibernate (bez korzystania z sesji statlese)?

+0

Dokładnie co było twoim pierwszym wyjątkiem? Ponadto, jeśli wykonasz 'Flush' * w pętli *, nie będziesz niczego grupować. –

+0

@Diego Mijelshon dodał wiadomość wyjątku – deamon

+0

@deamon jest to wielowątkowe w jakikolwiek sposób? – Newbie

Odpowiedz

1

Dlaczego wyczyścisz sesję?

Myślę, że nie należy usuwać sesji w pętli. Aby upewnić się, że zmiany zostały zapisane w bazie danych, wolałbym użyć transakcji.

Pseudokod:

foreach (var i in allElements) 
{ 
    using (var tx = session.BeginTransaction()) 
    { 
     ... do what you have to do with the object 
     tx.Commit(); 
    } 
} 

Aby przyspieszyć istnieją inne rzeczy, które mogą pomóc - trzeba określić, co naprawdę chcesz robić w pętli.

35

Po powinny działać,

var testObjects = CreateTestObjects(500000); 

var stopwatch = new Stopwatch(); 
stopwatch.Start(); 
using (IStatelessSession session = sessionFactory.OpenStatelessSession()) 
using (ITransaction transaction = session.BeginTransaction()) 
{ 
    foreach (var testObject in testObjects) 
     session.Insert(testObject); 
    transaction.Commit(); 
} 

stopwatch.Stop(); 
var time = stopwatch.Elapsed; 

Ref: http://nhibernate.info/blog/2008/10/30/bulk-data-operations-with-nhibernate-s-stateless-sessions.html

+1

+1 Jak należy odpowiedzieć! Zaoszczędziłeś czas – user919426

+0

Czy powinienem wyczyścić pamięci podręczne po użyciu sesji bezpaństwowej? A może sesje stanowe wychwycą zmiany wprowadzone przez sesję bezpaństwową? –

4

Wszystkie powyższe wskazówki są bardzo ważne i bardzo przydatne. Chciał dodać jeden do kolekcji: wyłączyć rejestrowanie. Posiadanie twojego SQL pokazanego w konsoli spowalnia zauważalnie, podobnie jak profilowanie za pomocą NHProf, automatyczne komentowanie i ładne formatowanie SQL logowanego przez NLog lub log4net. W naszym przypadku ustawienie:

cfg.AutoCommentSql = false; 
cfg.LogFormattedSql = false; 

zmniejszyło nasz czas wkładki luzem z ~ 6 sekund do nieco ponad 1 sekundy. Więc podczas rejestrowania potencjalnie pomoże Ci przygnieść poważniejsze problemy, przychodzi z hitem wydajności własnej!

Powiązane problemy