webForumDet fria alternativet

Optimering: Databashämtningspool?

.NET

30 svar · 1 607 visningar · startad av Lukaspojken · sida 2 av 2

Frågan, av Lukaspojken

I traditionell asp så tjänade man enormt på att ha en databashämtningspool, dvs en pool där man öppnade databasen, gjorde alla hämtningarna man behövde och sen stängde databasen så fort som möjligt. När jag programmerar i .net i en fyrskiktad miljö så känns det på något sätt fel :) Det blir dock mer struktur men det känns som att det är något som inte riktigt stämmer men jag kanske har fel. För v

Läs frågan i sin helhet →
Medlem sedan dec. 19996 522 inlägg
#21

Walker, innebär inte ditt sätt att den som sitter och skriver presentationlagret måste ha kännedom om din databashantering.

Medlem sedan okt. 2002188 inlägg
#22

Lukaspojken skrev:

-> Walker
Det är väldigt intressant det du tar upp och om jag förstår dig rätt så kör du också en skiktad lösning. Finns det några nackdeler med att köra denna lösning istället för den som Gladh och PDahlen förespråkar att man ska använda? Vad säger Gladh och Patrik själva? Det skulle vara intressant att få höra era synpunkter.

Jag tycker att Walker är inne på något som jag gärna skulle vilja spinna vidare på. Kommentarer först :)

Hej

Ett problem är att man får typomvandla allting som man får ut från loadmetoder. Ett annat problem är lazyload, dvs du laddar bara objekten när du behöver dem. Nu vet du kanske vad det är men.. Säg att du vill ladda upp en lastbil från databasen, men du vill inte ladda alla platser som den varit på, du laddar endast dessa då du behöver dem. I propertyn för platser finns då tex..

public IList Locations
{
get
{
If (_locations == null) this._locations = uow.LoadList(typeof(location), this)
return _locations
}
osv.

Då laddas ju alla plaster för den aktuella lastbilen. Men nu vet detta objekt om hur det laddas från databasen vilket ett vanligt objekt inte vet, så det blir att man blandar lite olika tänkande. (Ser inte detta som något problem egentligen men man blandar olika tänkesätt, tycker jag) Men skillnaden mellan de olika sätten är egentligen väldigt lite, kan tänka mig att ett vanligt utseende på en load metod ser ut något som

private static User Load(int id)
{
return uow.LoadUser(id) // eller return (User)uow.Load(typeof(user), id);
}

och sen i datamanager så skapar du en connection som du använder som vanligt. Lyft ut denna som ett property så kan du göra så som jag skrev i mitt förra inlägg. Lägg bara till så att loadmetoden eller alla metoder som gör något mot databasen kontrollerar hur du öppnade anslutningen, om den öppnades från den aktuella metoden eller om den öppnades utifrån. Jag tror att det finns något attribut som kan hjälpa till och att styra detta, ojb.net använder sig av något sorts attribut för att styra transactions, men aldrig riktigt förstått vad det gör och hur det fungerar.

Medlem sedan okt. 2002188 inlägg
#23

erka skrev:

Walker, innebär inte ditt sätt att den som sitter och skriver presentationlagret måste ha kännedom om din databashantering.

Jo, man kommer att se en fasad mot datalagret. Men kommer du inte alltid att se det på ett eller annat sätt?

User.Load(id), User.Save() osv.. Dessa metoder är ju i princip samma som jag har i min datamanager(uow i förra exemplet).

Visst dessa metoder skulle du kunna kapsla in så att du döljer all databashantering helt och hållet, men är det värt all den tid och jobb som det innebär?

Medlem sedan maj 20012 812 inlägg
#24

uow.OpenConnection()
uow.Load(obj1);
uow.Load(obj2);
setUserName(obj2);
uow.Save(obj2);
uow.CloseConnection();

Just en sådan här lösning är riktigt illa ur skalbarhetssynpunkt och även då lite prestanda. Jag har förklarat det tidigare och vet inte om jag orkar en gång till, kommer dock en liten kortfattade förklaring.

En databaskoppling skall vara upptagen så kort tid som möjligt. Mina databaskopplingar är "aldrig" upptagen utanför DAL:et. (Givetviss har jag de öppna längre som exemplet ovan när jag jobbar med transactioner). Anledningen till det är att det tar inte speciellt långtid att använda en koppling som ligger i poolen och väntar, det som tar tid är att skapa en ny när alla i poolen är upptagna.

Om du nu tittar på exemplet ovan så görs 4 metod anrop på samma koppling. Istället för att öppna.. använd.. stäng, öppna.. använd.. stäng osv osv. Med mitt sätt måste man använda 4 olika kopplingar som alla ligger i poolen, alltså tar de inte längre tid än att använda 1 och samma, men vinsten finns i att jag minimerar risken att jag skall binda upp alla kopplingar i poolen. Och allting beror på att du inte kan styra själv när din kod skall exekveras.

Som default kan ASP.NET hantera 25 trådar, alltså de kan exekvera 25 sidor samtidigt, det är givetviss lögn efter som endast 1 sida kan processas av processorn åtgången, de andra 24 väntar tills deras tur kommer. Eftersom man inte kan påverka när trådarna skall skiftas så blir det så att man skiftar tråd när de olika methoderna körs, alltså binder man upp en databaskoppling i onödan, med mitt exempel så är chansen större att man gör en trådskift när jag inte har en databaskoppling öppen och binder alltså inte upp lika många kopplingar alltså bättre skalbarhet och prestanda.

Sedan tycker jag inte att man i sitt Bizlager skall öppna och stänga databasen, det skall DAL:et sköta, enda gången man skall göra det är när man använder transactioner eftersom man då måste göra flera anrop mot samma öppna koppling.

Själva iden med O/R Mappers som Walker beskriver i korthet är att man kapslar in sina databasanrop i ett lager mellan ditt BizLib och DAL:et. Vilket gör att du aldrig någonsin skriver ett SQL Satement mot din databas. Extremt OO, och underhållsmässigt samt skalbart, betydligt sämre ur prestandasynpunkt.

- Magnus

Medlem sedan okt. 2002188 inlägg
#25

Gladh skrev:

uow.OpenConnection()
uow.Load(obj1);
uow.Load(obj2);
setUserName(obj2);
uow.Save(obj2);
uow.CloseConnection();

Just en sådan här lösning är riktigt illa ur skalbarhetssynpunkt och även då lite prestanda. Jag har förklarat det tidigare och vet inte om jag orkar en gång till, kommer dock en liten kortfattade förklaring.

En databaskoppling skall vara upptagen så kort tid som möjligt. Mina databaskopplingar är "aldrig" upptagen utanför DAL:et. (Givetviss har jag de öppna längre som exemplet ovan när jag jobbar med transactioner). Anledningen till det är att det tar inte speciellt långtid att använda en koppling som ligger i poolen och väntar, det som tar tid är att skapa en ny när alla i poolen är upptagna.

Om du nu tittar på exemplet ovan så görs 4 metod anrop på samma koppling. Istället för att öppna.. använd.. stäng, öppna.. använd.. stäng osv osv. Med mitt sätt måste man använda 4 olika kopplingar som alla ligger i poolen, alltså tar de inte längre tid än att använda 1 och samma, men vinsten finns i att jag minimerar risken att jag skall binda upp alla kopplingar i poolen. Och allting beror på att du inte kan styra själv när din kod skall exekveras.

Som default kan ASP.NET hantera 25 trådar, alltså de kan exekvera 25 sidor samtidigt, det är givetviss lögn efter som endast 1 sida kan processas av processorn åtgången, de andra 24 väntar tills deras tur kommer. Eftersom man inte kan påverka när trådarna skall skiftas så blir det så att man skiftar tråd när de olika methoderna körs, alltså binder man upp en databaskoppling i onödan, med mitt exempel så är chansen större att man gör en trådskift när jag inte har en databaskoppling öppen och binder alltså inte upp lika många kopplingar alltså bättre skalbarhet och prestanda.

Sedan tycker jag inte att man i sitt Bizlager skall öppna och stänga databasen, det skall DAL:et sköta, enda gången man skall göra det är när man använder transactioner eftersom man då måste göra flera anrop mot samma öppna koppling.

Själva iden med O/R Mappers som Walker beskriver i korthet är att man kapslar in sina databasanrop i ett lager mellan ditt BizLib och DAL:et. Vilket gör att du aldrig någonsin skriver ett SQL Satement mot din databas. Extremt OO, och underhållsmässigt samt skalbart, betydligt sämre ur prestandasynpunkt.

- Magnus

God morgon..

Jag måste hålla med Gladh efter att gjort lite tester. Det sättet som jag beskrev är inte alls bra med tanke på trådarna. Det lustiga är att jag testade en massa scenario innan som visade att även om en uppkoppling fanns i poolen så tog det bra mycket extra tid att få tag på den än att använda samma anslutning igen, men så är det ju inte..

Medlem sedan maj 20011 312 inlägg
#26

Du gav dig för lätt Walker :) Närå, det låter vettigt Magnus men om vi tittar på det här med skiktade lösningar. Finns det något generellt som du tror skulle göra att man tjänade en hel del prestanda på om man byggda den skiktade lösningen på det sättet enligt det? Har du några tankar kring det Magnus eller någon annan?

Medlem sedan apr. 2004778 inlägg
#27

När det gäller skiktade lösningar och prestanda så handlar det om persistance. Alltså att hålla kvar objekt för att slippa hämta i databasen och återskapa.
En O/R mapper sköter det åt dig, om du bygger egna lager så får du lägga in det själv i form av Cache, State, Session.

Så bestäm dig för vilken lösning du vill ha. Om du vill ha en skiktad lösning så läs på allt du kan om Cache.

Medlem sedan maj 20012 812 inlägg
#28

Prestanda förlusten att använda skiktadelösningar är inte speciellt stor (knappast märkbar), så länge skikten ligger på samma maskin. Flyttar du ut skikten på olika maskiner så får du en massa nätverkstrafik och detta snor prestanda.

Precis som Patrik skriver så är Cachen vägen till bra prestanda. Och då så nära användaren som möjligt. Du vinner mer i prestanda om du kan cacha i GUI än i ditt DAL eftersom du då slipper gå ner genom flera skikt för att hämta just ditt objekt. Det är dock en avvägning, då risken för korupt data är större ju närmare du cachar användaren.

Skall du syssla mycket med OO så införskaffa dig en O/R Mapper, skall du bara presentera rå data på en websida i stor gridar, så binder du dataTables till en Repeater där du låter ditt DAL returnera DataTables. Det är en vis prestanda förlust med ett datatable jämfört med en DataReader, men samtidigt så kapslar du in ditt DAL fullständigt och slipper stäng din databaskoppling i ditt GUI.

- magnus

Medlem sedan okt. 2002188 inlägg
#29

Lukaspojken skrev:

Du gav dig för lätt Walker :) Närå, det låter vettigt Magnus men om vi tittar på det här med skiktade lösningar. Finns det något generellt som du tror skulle göra att man tjänade en hel del prestanda på om man byggda den skiktade lösningen på det sättet enligt det? Har du några tankar kring det Magnus eller någon annan?

Hehe.. Anledningen till att jag ibland gör som jag gör i mitt förra exemplet är att jag hade ett program där jag fick en massa problem med prestandan pga att jag öppnade och stängde en dbkoppling hela tiden. Men sen skrev gladh att det inte var något problem så jag gjorde lite tester och kunde inte på något sätt se/ få fram något problem. Och jag har inte en aning om varför det blev problem i det programmet som jag faktiskt fick problem med.

Så därför så blir det svårt att säga att jag har rätt när jag inte på något sätt, förutom tjurighet :), kan styrka det.

Medlem sedan maj 20012 812 inlägg
#30

jag hade ett program där jag fick en massa problem med prestandan pga att jag öppnade och stängde en dbkoppling hela tiden

Om man inte använder Connectionpoolen så får du det problemet, mycket möjligt att du lyckats disable den för det programmet.

- M

Medlem sedan maj 20012 812 inlägg
#31

Hittade denna sida för de som är prestandafreakar...

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt06.asp

Där finns matnyttiga saker, samt saker som man kanske skall tänka sig för innan man implementerar...

- M

275 ms totalt · 4 externa anrop · v20260731065814-full.1dc6f849
133 ms — deklarationer (db)
0 ms — hämta statistik (cache)
139 ms — hämta tråd, inlägg och bilagor (db)
133 ms — ändringar (db)