[C#.NET] NHibernate - Langzaam

Pagina: 1
Acties:
  • 226 views sinds 30-01-2008
  • Reageer

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Facer
  • Registratie: Januari 2002
  • Niet online

Facer

Ken net.....

Topicstarter
Ben al een paar dagen bezig met een eigen project te koppelen met NHibernate. Alles werkt naar behoren alleen het toevoegen van items gaat zeer langzaam (interval per 100 toegevoegde items):
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
Item 100 completed in: 3,828125 sec. (Vanwege alles opstarten langzaam)
Item 200 completed in: 0,65625 sec.
Item 300 completed in: 0,546875 sec.
Item 400 completed in: 0,734375 sec.
Item 500 completed in: 0,875 sec.
Item 600 completed in: 1,078125 sec.
Item 700 completed in: 1,203125 sec.
Item 800 completed in: 1,125 sec.
Item 900 completed in: 1,125 sec.
Item 1000 completed in: 1,359375 sec.
Item 1100 completed in: 1,3125 sec.
.....
Item 100.000 completed in: 60,548 sec

Heb vannacht het programma laten draaien en toen die rond de 100.000 items zat duurde het 60 seconden om 100 items toe te voegen aan de database. Ik maak gebruik van een MySQL 5 database en de engine die ik voor de tabel gebruik is MyISAM .

De manager VillageManager
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  public class VillageManager
  {
    static Configuration config;
    static ISessionFactory factory;
    private ISession session;

    public ISession Session
    {
      get
      {
        if (session == null || !session.IsOpen)
        {
          try
          {
            session = factory.OpenSession();
          }
          catch (Exception ex)
          {
            throw new Exception("The session or database connection could not be created", ex);
          }
        }
      return session;
      }
    }

    public VillageManager()
    {
      try
      {
        config = new Configuration();
        config.AddClass(typeof(Database.EntityVillage));
        factory = config.BuildSessionFactory();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
    }

    public void SaveVillage(EntityVillage village)
    {
      ITransaction tx;
      try
      {
        Session.Reconnect();
        tx = Session.BeginTransaction();
        Session.Save(village);
        tx.Commit();
      }
      catch (Exception ex)
      {
        Console.WriteLine(ex.Message);
      }
      finally
      {
        Session.Flush();
        Session.Disconnect();
      }
    }
  }


Deze manager word vanuit de business maar 1x aangeroepen en word steeds de functie SaveVillage() gebruikt om de Village's toe te voegen.

Op internet heb ik al een artikel gelezen dat je de Configuration en ISessionFactory static moet maken voor snellere verwerking van de gegevens. Maar toch blijft die in mijn ogen langzaam functioneren. Wat doe ik fout of hoort deze steeds grotere vertraging bij NHibernate?

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
Ben je zeker dat de vertraging bij NHibernate ligt, en niet bij je DBMS ?

Als je al een aantal items hebt toegevoegd, zal je DBMS nl. ook iedere keer wat werk hebben om z'n indexen bij te werken. Ik ben ook niet genoeg bekend met MySQL, maar in SQL Server heb je zoiets als een clustered key, die de opslagvolgorde van de records bepaald. Als je geen goed gekozen 'clustered key' hebt, dan heeft het DBMS bij iedere insert werk om de opslagvolgorde van de records te gaan veranderen.

Daarnaast denk ik, heb je ook veel vertraging door bij iedere 'save' je connectie te openen en te sluiten:
open connectie - save - close

Is het, in dit geval (als je weet dat je echt 1000den items na elkaar moet saven, en ertussen niets gebeurt), niet beter om een soort van 'BulkSaveVillage' method te maken waarin je dit doet:

- open NHibernate Session
- start transactie
- save alle entities (1000, 100.000 whatever)
- commit transactie
- close sessie

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Facer
  • Registratie: Januari 2002
  • Niet online

Facer

Ken net.....

Topicstarter
Dank je voor je snelle reactie zo op oudjaarsdag.

Aan de hand van je advies een functie gemaakt die om de 200 items word aangeroepen:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    public void SaveVillage(IList entityVillageList)
    {
      ITransaction trans;
      DateTime startTime = DateTime.Now;
      try
      {
        if(entityVillageList == null)
          throw new NullReferenceException("EntityVillageList is null");
        if (!Session.IsConnected)
        {
          Session.Reconnect();
        }
        Console.WriteLine(String.Concat("Session connected in: ", ((TimeSpan)DateTime.Now.Subtract(startTime)).TotalSeconds).ToString());
        startTime = DateTime.Now;

        trans = session.BeginTransaction();
        Console.WriteLine(String.Concat("Transaction started in: ", ((TimeSpan)DateTime.Now.Subtract(startTime)).TotalSeconds).ToString());
        startTime = DateTime.Now;

        foreach(object entityVillage in entityVillageList)
            session.Save(entityVillage);
        Console.WriteLine(String.Concat("Items saved: ", ((TimeSpan)DateTime.Now.Subtract(startTime)).TotalSeconds).ToString());
        startTime = DateTime.Now;

        trans.Commit();
        Console.WriteLine(String.Concat("Commit in: ", ((TimeSpan)DateTime.Now.Subtract(startTime)).TotalSeconds).ToString());
        startTime = DateTime.Now;
      } 
      catch (Exception ex)
      {
        //trans.Rollback();
        Console.WriteLine(ex.Message);
      }
      finally
      {
        Session.Flush();
        Session.Disconnect();
      }
    }


Weer de nodige timers in gezet om het in de gaten te houden:
code:
1
2
3
4
5
6
7
8
9
10
11
12
Item 100 completed in: 0,484375
Item 200 completed in: 0
Session connected in: 0
Transaction started in: 2,84375
Items saved: 0,03125
Commit in: 0,25
Item 300 completed in: 3,125
Item 400 completed in: 0
Session connected in: 0
Transaction started in: 0
Items saved: 0
Commit in: 0,1875


Dat ik eerst steeds me sessie sluit en open zet zou inderdaad vertraging kunnen opleveren maar dan is het vreemd waarom de vertraging dan exponent oploopt. De code zal ik vanavond weer laten draaien maar met de eerste 1000 items is er toch een grote snelheid winst behaald. Bedankt voor je hulp _/-\o_

Ik zal morgen nog een bericht toevoegen of deze manier ook goed werkt als ik de 100.000 items heb toegevoegd aan de database.

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 11:22
Het zou, denk ik, nog beter zijn als je uw SaveVillage method een session oid meegeeft als parameter.
Op die manier kan je die SaveVillage method gebruiken voor n - aantal entities. En de component / class / fucntie waar je die method oproept, bepaalt dan ook meteen dat de sessie moet geopend & geclosed worden.

en nu , nu ben ik weg :P

[ Voor 4% gewijzigd door whoami op 31-12-2007 17:43 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Facer
  • Registratie: Januari 2002
  • Niet online

Facer

Ken net.....

Topicstarter
Heb zonet toch maar even het programma laten draaien en zie resultaat (alles in seconden):
Session connected in:0
Transaction started in:0
Commit in:1,84375
Item 85000 to 86000 completed in:2,8125

Vannacht was die pas om de +- 50.000 na 12 uur 8)7
Nu heeft die alles in +- 10 minuten gedaan maximaal.

Bedankt nog voor je tweede tip. Ik zal er morgen dat stukje ook optimaliseren. Harstikke bedankt en gelukkig nieuwjaar :D