Co jest szybsze ASP.NET MVC z EF 6 czy JAVA WEB APPLICATION i JPA

Odpowiedz Nowy wątek
2018-06-13 14:26
0

Mam pytanie o powyższej treści co jest szybsze, dokonałem bowiem testów wydajnościowych dla porównania dwóch identycznych aplikacji, jednej napisanej w ASP.NET MVC z użyciem EF6 struktura tej aplikacji zbudowana jest z czterech modułów

Modułu Danych
Modułu Repozytorium
Modułu Serwisów
Modułu Web MVC

Druga aplikacja została napisana w JEE, jej struktura jest typowa dla JEE czyli kontrolery, ziarna EJB, facade, Java Web Application z użyciem EclipseLink.

Tryb wczytania encji, w obu aplikacjach był ustawiony na LAZY.

Aplikację ASP.NET wdrożyłem na serwer IIS przy pomocy opcji Publish w Visual Studio i testowałem na bazie utworzonej w MS SQL Server.

Do tej samej bazy była podłączona też aplikacja Java Web Application wdrożona na serwer GlassFish.

I tu mnie wynik zaskoczył,

tworzenie 1000 rekordów nagłówków dokumentu i 3000 pozycji w pętli, aplikacja Javy wykonała 40 razy szybciej niż aplikacja w ASP.NET

odczytywanie pojedynczych encji czyli 1000 dostawców, 3000 towarów i 1000 dokumentów, aplikacja Javy wykonała 3,5 razy szybciej niż aplikacja w ASP.NET,

przy wczytaniu list encji różnica była mniejsza 1,3 na korzyść Java

Testy wykonane były na maszynie wirtualnej restartowanej po każdym teście

Różnica w szybkości tworzenia rekordów zszokowała mnie to jakiś błąd ? Jakie są Państwa doświadczenia ?

przykład funkcji dodającej dokumenty w ASP.NET

public void testUtworzDokumntyPz()
        {

            long mIdDostawcy = 1;
            long mIdTowaru = 1;
            long mIdNaglowkaPz = 1;

            decimal ilosc = 1;
            decimal cenaZakupuNetto = 1;
            int stawkaVat = 7;

            ObslugaDanych<TOWARY> TowaryFacade = new ObslugaDanych<TOWARY>(Context);
            ObslugaDanych<POZYCJE_PZ> PozycjeDokumentowPZFacade = new ObslugaDanych<POZYCJE_PZ>(Context);
            ObslugaDanych<MAGAZYNY> MagazynyFacade = new ObslugaDanych<MAGAZYNY>(Context);
            ObslugaDanych<DOSTAWCY> DostawcyFacade = new ObslugaDanych<DOSTAWCY>(Context);
            NaglowkiDokumentowPZObslugaDanych NaglowkiDokumentowPZFacade = new NaglowkiDokumentowPZObslugaDanych(Context);
            ObslugaDanych<TESTY> TestyFacade = new ObslugaDanych<TESTY>(Context);

            NAGLOWKI_PZ NaglowkiPz;
            MAGAZYNY magazyn;

            List<POZYCJE_PZ> pozycjePzList;
            POZYCJE_PZ pozycjaPz;
            NAGLOWKI_PZ naglowekPz;

            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();

            for (int mIdMagazynu = 1; mIdMagazynu <= 10; mIdMagazynu++)
            {

                magazyn = MagazynyFacade.getWiersz(mIdMagazynu);

                for (int mNrPz = 1; mNrPz <= 100; mNrPz++)
                {
                    NaglowkiPz = new NAGLOWKI_PZ();

                    NaglowkiPz.NR_PZ = mNrPz;

                    NaglowkiPz.ROK_PZ = 2018;

                    NaglowkiPz.ID_MAGAZYNU = mIdMagazynu;

                    NaglowkiPz.ID_DOSTAWCY = mIdDostawcy;

                    NaglowkiPz.DATA_PZ = DateTime.Now;

                    NaglowkiPz.MAGAZYNY = magazyn;

                    NaglowkiPz.DOSTAWCY = DostawcyFacade.getWiersz(mIdDostawcy);

                    NaglowkiDokumentowPZFacade.dodajWiersz(NaglowkiPz);

                    mIdDostawcy++;

                }

            }

            for (int mIdMagazynu = 1; mIdMagazynu <= 10; mIdMagazynu++)
            {

                for (int mNrPz = 1; mNrPz <= 100; mNrPz++)
                {

                    pozycjePzList = new List<POZYCJE_PZ>();
                    naglowekPz = NaglowkiDokumentowPZFacade.getWiersz(mIdNaglowkaPz);

                    for (short nrPozycji = 1; nrPozycji <= 3; nrPozycji++)
                    {

                        pozycjaPz = new POZYCJE_PZ();

                        pozycjaPz.ID_NAGLOWKA_PZ = mIdNaglowkaPz;
                        pozycjaPz.NAGLOWKI_PZ = naglowekPz;
                        pozycjaPz.NR_POZYCJI = nrPozycji;
                        pozycjaPz.ID_TOWARU = mIdTowaru;
                        pozycjaPz.TOWARY = TowaryFacade.getWiersz(mIdTowaru);

                        pozycjaPz.ILOSC = ilosc;
                        pozycjaPz.ILOSC_AKTUALNA = ilosc;
                        pozycjaPz.CENA_ZAKUPU_NETTO = cenaZakupuNetto;
                        pozycjaPz.STAWKA_VAT = stawkaVat;

                     //   ilosc += (decimal)0.01;
                     //   cenaZakupuNetto += (decimal)0.01;

                        pozycjaPz = PozycjeDokumentowPZFacade.dodajWierszIZwroc(pozycjaPz);

                        pozycjePzList.Add(pozycjaPz);
                        mIdTowaru++;

                    }

                    naglowekPz.POZYCJE_PZ = pozycjePzList;
                    NaglowkiDokumentowPZFacade.edytujWiersz(naglowekPz);

                    mIdNaglowkaPz++;

                }

            }

            watch.Stop();

            TESTY test = new TESTY();
            test.TYP_TESTU = "DODAJ_PZ";
            test.CZAS = watch.ElapsedMilliseconds;
            test.CZAS_TAKTOWANIE = watch.ElapsedTicks;
            TestyFacade.dodajWiersz(test);

        }
edytowany 1x, ostatnio: Pawel412, 2018-06-13 14:30

Pozostało 580 znaków

2018-06-13 16:46
0

Nie wiem czy AD 2018 kogoś taki temat jeszcze rozpala ale jak już coś twierdzisz to wrzuć kod i podaj dokładne wyniki. Może komuś się zechce to powtórzyć. Chociaż nie wiem po co.

Pozostało 580 znaków

2018-06-13 16:50
0

Poza tym, że kod wygląda naprawdę groźnie, to bez wiedzy o tym, jak masz skonfigurowane ORMy i o co chodzi z tymi "fasadami" ciężko cokolwiek stwierdzić. Np. jeśli u Ciebie getWiersz za każdym razem pobiera coś z bazy, to oczywiste, że będzie wolne. Ważna jest też liczba oddzielnych transakcji. W kodzie, który wkleiłeś nie ma żadnego commita, więc pewnie robisz to w każdej metodzie dodajWiersz. Mam rację? Wersja Javowa też tak robi?

Ale może to faktycznie są identyczne aplikacje, EF z prędkości raczej nie słynie. Ale co konkretnie jest problemem w takiej sytuacji może powiedzieć tylko profiler.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-06-13 18:04
0

konfiguracja ORM jest standardowa ustalona domyślnie odpowiednio w Visual Studio i NetBeans

kod dodajWiersz

namespace HurtowniaData.HurtowniaEntities
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class HURTOWNIAEntities : DbContext
    {
        public HURTOWNIAEntities()
            : base("name=HURTOWNIAEntities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public virtual DbSet<DOSTAWCY> DOSTAWCies { get; set; }
        public virtual DbSet<KLIENCI> KLIENCIs { get; set; }
        public virtual DbSet<MAGAZYNY> MAGAZYNies { get; set; }
        public virtual DbSet<NAGLOWKI_MM> NAGLOWKI_MM { get; set; }
        public virtual DbSet<NAGLOWKI_PZ> NAGLOWKI_PZ { get; set; }
        public virtual DbSet<NAGLOWKI_WZ> NAGLOWKI_WZ { get; set; }
        public virtual DbSet<NUMERY_DOKUMENTOW> NUMERY_DOKUMENTOW { get; set; }
        public virtual DbSet<NUMERY_POZYCJI_DOKUMENTOW> NUMERY_POZYCJI_DOKUMENTOW { get; set; }
        public virtual DbSet<POZYCJE_MM> POZYCJE_MM { get; set; }
        public virtual DbSet<POZYCJE_PZ> POZYCJE_PZ { get; set; }
        public virtual DbSet<POZYCJE_WZ> POZYCJE_WZ { get; set; }
        public virtual DbSet<STANY> STANies { get; set; }
        public virtual DbSet<TESTY> TESTies { get; set; }
        public virtual DbSet<TOWARY> TOWARies { get; set; }
    }
}

namespace HurtowniaRepositories
{
    public class ObslugaDanych<TEncja> : IObslugaDanych<TEncja> where TEncja : class

    {
        protected DbContext Context;

        public ObslugaDanych(DbContext context)
        {
            Context = context;
        }

        public TEncja getWiersz(long id)
        {

            return Context.Set<TEncja>().Find(id);

        }

      .......................

        public void dodajWiersz(TEncja entity)
        {
            Context.Set<TEncja>().Add(entity);
            Context.SaveChanges();

        }

        public TEncja dodajWierszIZwroc(TEncja entity)
        {
            Context.Set<TEncja>().Add(entity);
            Context.SaveChanges();
            return entity;
        }

        public void dodajWiersze(IEnumerable<TEncja> entities)
        {
            Context.Set<TEncja>().AddRange(entities);
        }

        .................................................

        public void zwolnijContext()
        {
            Context.Dispose();
        }
    }
}

Pozostało 580 znaków

2018-06-13 18:14
1

Czyli dokładnie jak zostało już wcześniej wspomniane, przy każdym odczycie i zapisie robisz to pojedynczymi operacjami na bazie.
Nie jestem pewny jak faktycznie wygląda obecnie sytuacja z EF, ale kiedyś miał tendencje do przymulania względem odpowiedników, także wcale by mnie nie zdziwiło, gdyby faktycznie wychodził wolniej.
Natomiast kwestia standardowej konfiguracji ORMów też nadal nie jest wyjaśniona, bo trzeba by się zagłębić czy defaultowe ustawienia zwyczajnie się nie różnią, co powoduje na przykład domyślne wrapowanie dużej ilości zapytań w transakcję w przypadku Javy.

Weź do łapy Hibernate i nHibernate, skonfiguruj je identycznie i wtedy się baw, bo jak nie wiesz nawet co się dzieje pod spodem, to porównania nie mają sensu.

I nadal nie mamy dokładnych wyników, więc możemy co najwyżej wierzyć na słowo ;)

I... Kod faktycznie nie zachęca do zapoznawania się. Czemu zdecydowałeś się użyć języka polskiego z próbą zliczbomnożenia z angielskiego?

edytowany 1x, ostatnio: Klojtex, 2018-06-13 18:15

Pozostało 580 znaków

2018-06-13 19:01
0

A w wersji Javowej też commitujesz po każdym rekordzie?


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2018-06-13 19:14
0

w nagłówkach używam metody facade create(entity)

a dla pozycji poniżej dzięki temu mogę zwrócić encje i dodać do listy pozycji dołączanej do nagłówka

public PozycjePz dodajNowaPozycjePzIZwroc(PozycjePz obiektPozycjaPz) {

        getEntityManager().persist(obiektPozycjaPz);
        getEntityManager().flush();
        return obiektPozycjaPz;

    }
edytowany 1x, ostatnio: Pawel412, 2018-06-13 19:14

Pozostało 580 znaków

2018-06-13 19:39
0

To jak dodawać rekordy w EF by nie dokonywać zapisu po każdej metodzie ?

Pozostało 580 znaków

2018-06-13 19:47
1

Rozdzielając dodawanie encji do kolekcji kontekstu od zapisywania ich do bazy.
Jeśli masz kontekst wpinany jako zależność klasy, to

context.SaveChanges()

Będzie w osobnej metodzie niż

context.Set<T>.Add(encja)

Normalnie robi się to jeszcze inaczej, ale to nie ten temat.

Pozostało 580 znaków

2018-06-13 19:49
1

Tak jak się to robi korzystając z ORMa - wykonać wszystkie operacje w ramach unit of work, zatwierdzić na koniec.
Przy czym Ty tu robisz operacje wsadowe, ORMy generalnie do nich nie służą. EF pewnie klęknie od nadmiaru śledzonych obiektów, więc trzeba to podzielić na jakieś pakiety może. Ale najpierw spróbuj normalnego podejścia z jednym UoW.


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."
edytowany 1x, ostatnio: somekind, 2018-06-13 19:49

Pozostało 580 znaków

2018-06-13 19:58
0

moim celem było porównać wydajność dodawania nowych rekordów przez JPA w moim wypadku EclipseLink i EF

jest lepszy sposób ?

nie mam dużego doświadczenia w ASP.NET, normalne podejście to znaczy w tym wypadku ?

edytowany 2x, ostatnio: somekind, 2018-06-13 21:32

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 0, botów: 1

Robot: Yandex