webForumDet fria alternativet

flera frågor under samma connection

.NET

15 svar · 603 visningar · startad av Nöff

Medlem sedan nov. 2003569 inlägg
Frågan#1

OleDbCommand mycommand=new OleDbCommand();
mycommand.Connection=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databas.mdb;User Id=admin;Password=;");

	mycommand.Connection.Open();

	mycommand.CommandText="DELETE \* FROM kunder";
	mycommand.ExecuteNonQuery();

	mycommand.CommandText="DELETE \* FROM uppringningar";
	mycommand.ExecuteNonQuery();

	mycommand.CommandText="DELETE \* FROM sparade_svar";
	mycommand.ExecuteNonQuery();

mycommand.CommandText="SELECT * FROM sparade_svar";
OleDbDataReader reader=mycommand.ExecuteReader();

	mycommand.Connection.Close();
	mycommand.Connection.Dispose();
	mycommand.Dispose();

Är det OK att ställa flera frågor till databasen under samma "öppning"? , även också ställa flera SELECT ?, eller måste jag stänga efter varje fråga och öppna den på nytt om jag vill ställa en till fråga?

Medlem sedan apr. 20022 743 inlägg
#2

Kan inte ASP.NET men det måste ju gå att ställa fler frågor i det, går ju i alla andra språk. Dessutom är det bli väldigt prestandakrävande om du skulle vara tvungen att öppna och stänga databasen flera gånger.

Medlem sedan maj 20012 812 inlägg
#3

Det går alldeles utmärkt att göra som du gör. Men i motsats till Poffe, så skulle jag nog rekomender att öppna - fråga - stäng. På varje fråga.

Orkar inte dra hela förklaringen en gång till, sök på forumet, har förklarat flera gånger redan, men det är inte mer prestandakrävande att göra på mitt sätt än på ditt. Och mitt sätt är bättre vid högre belastning.

- M

Medlem sedan feb. 200112 078 inlägg
#4

Med risk att verkar lite korkad (för jag hittade inget om det i forumet), varför är det bättre att öppna/fråga/stänga på varje? Låter väldigt ologiskt, men jag antar att det finns en hake?

Medlem sedan dec. 20003 887 inlägg
#5

Connection pooling och många användare samtidigt.

Medlem sedan nov. 2003569 inlägg
#6

Ok, men hur ser då den absolut ultimata superduper säkra databaskopplingen ut då?.

Kan någon göra om min kod däruppe till den mest perfekta kopplingen tro? :)

Medlem sedan maj 20012 812 inlägg
#7

okej jag skall förklara varför det är bättre.

Du kan läsa om connection pooling som Engine refererar till och det är det som är nycklen till prestanda vinsten. Det förklara dock inte varför man inte skall göra en massa anrop utan att stänga emellan.

Förklaringen ligger i att du inte själv styr när koden skall exekveras, utan det gör trådhanteraren i OS:et. Säg att du skapar en ASP.NET sida, ASP-motor kan hantera 25 trådar per processor. Det betyder att man kan exekvera 25 sidor samtidigt. Säg nu att alla exekverar samma sida som ser ut så här (dummy sida jag vet, men det åskådligör exemplet bra)

OleDbCommand mycommand=new OleDbCommand();
mycommand.Connection=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databas.mdb;User Id=admin;Password=;");

mycommand.Connection.Open();

mycommand.CommandText="DELETE * FROM kunder";
mycommand.ExecuteNonQuery();

Thread.Sleep(5000) //-- Motsvarar något arbete på sidan, kanske någon stränghantering

mycommand.CommandText="DELETE * FROM uppringningar";
mycommand.ExecuteNonQuery();

Thread.Sleep(5000) //-- Motsvarar något arbete på sidan, kanske någon stränghantering

mycommand.CommandText="DELETE * FROM sparade_svar";
mycommand.ExecuteNonQuery();

mycommand.Connection.Close();
mycommand.Connection.Dispose();
mycommand.Dispose();

Om man tittar på koden nu så ser man att mellan de olika databasanropen så exekveras en massa kod, som tar en viss tid (i mitt exempel 5 sekunder :)) och det är här som man inser att det blir bättre att stänga kopplingen efter varje anrop.

Säg att person1 kommer in på sidan och kör den, då plockas en connection från poolen och denna behålls nu av denna person i minst 10 sekunder. När näste person kommer in så hämtas en connection från poolen och detta görs ända tills alla connection som finns i poolen är upptagna (default brukar vara 5). Så när person 6 kommer in så finns ingen ledig connection i poolen och det måste skapas en ny (detta tar tid). Osv osv tills alla 25 personer nu har koppling till databasen.

Som vi nu ser så mellan 2 anrop så gör vi något i 5 sekunder, vi använder inte databasen men har ändå en koppling mot den. Och det är dumt, eftersom vi då tar en koppling från poolen.

Om vi istället hade stängt vår koppling mot databasen precis efter vi har använt den, så hade det funnits en ledig koppling i poolen när någon hade behövt den. Om vi i vårt exempel har sådan tur att besökarna kommer precis så att det endast är 5 stycken åtgången som gör ett anrop medans de 20 andra håller på med arbete mellan anropen så skulle en connection pool med 5 kopplingar klara av att hanterar detta utan att skapa ny kopplingar (vilket tog tid). Detta kräver ju dock att vi lämmnar tillbaka vår koppling när vi inte behöver den. Alltså skall vi stänga vår koppling så fort vi inte behöver den.

Nu säger säkert någon att det var ju ett dumt exempel eftersom man inte gör något som tar så lång tid mellan anropen. För att se att detta inte spelar någon roll måsta man förstå att processorn använder trådar för att simulerar samtidighet. Ingen processor i världen kan processa mer än en instruktion samtidigt, man har en massa lösningar för att simulera så att det ser ut så att flera instruktioner exekveras samtidigt, och trådar är en sådan lösning.

Det betyder att lite kod för ett program körs, som sedan (innan det är klart) lämnar ifrån sig processorn till ett annat program som körs lite) som sedan lämnar tillbaka processorn till första programmet. Och eftersom man inte kan vet när en tråd körs eller när den lämnar ifrån sig processorn så kan det hända att en tråd gör ett anrop till databasen, och innan kalla på nästa anrop så kommer det andra trådar in och använder processorn.

Om man då lämnar ifrån sig kopplingen så frigör man resurser som kan användas när tråden sover.

Just i detta exempel som nöff visar så blir vinsten mindre än vid mitt exempel eftersom inga processor tunga operation utförs, men det kan ändå bli så att fler kopplingar än nödvändigt användas bara för att man inte stänger dem. Sedan är nöffs exempel inte riktigt verklighetstroghet eftersom man endast hade använt 1 command och istället skickat in alla 4 SQL satser som en till databasen.

Men återigen, eftersom man använder trådar och du inte själv bestämmer när dessa körs så kan du, om du inte öppnar - kör - stänger använda fler kopplingar än vad som egentligen är nödvändigt. Och det är skapandet av dessa extra kopplingar som kostar i skalbarhet och prestanda.

- M

kom på att det blev lite rörigt men hoppas någon förstår iallafall.

Medlem sedan maj 20012 812 inlägg
#8

Så fall hade jag gjort om det till 1 eller 2 frågor mot databasen.

OleDbCommand mycommand=new OleDbCommand();
mycommand.Connection=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databas.mdb;User Id=admin;Password=;");

mycommand.Connection.Open();
mycommand.CommandText="DELETE * FROM kunder;DELETE * FROM uppringningar;DELETE * FROM sparade_svar";
mycommand.ExecuteNonQuery();
mycommand.Connection.Close();

mycommand.Connection.Open();
mycommand.CommandText="SELECT * FROM sparade_svar";
OleDbDataReader reader=mycommand.ExecuteReader();
mycommand.Connection.Close();

mycommand.Connection.Dispose();
mycommand.Dispose();

Borde fungera bra.

- M

Medlem sedan nov. 2003569 inlägg
#9

OK, men om man behöver göra 10 frågor mot databasen vilket inkluderar både SELECT UPDATE och INSERT. Ska man göra på samma sätt då?.

Medlem sedan sep. 20011 914 inlägg
#10

Har ingen aning om vad du gör med din kod, men borde det inte räcka med koden nedan. För frågan i den andra connectionen borde ju inte retunera något då du innan tagit bort allt från tabellen sparade_svar.

OleDbCommand mycommand=new OleDbCommand();
mycommand.Connection=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=databas.mdb;User Id=admin;Password=;");

mycommand.Connection.Open();
mycommand.CommandText="DELETE * FROM kunder;DELETE * FROM uppringningar;DELETE * FROM sparade_svar";
mycommand.ExecuteNonQuery();
mycommand.Connection.Close();

mycommand.Connection.Dispose();
mycommand.Dispose();

red// kanske lite ot då det inte har med trådens rubrik att göra, men iaf...

Medlem sedan nov. 2003569 inlägg
#11

Den där sql-koden var bara ett exempel som jag kom på för att visa på ett problem, inget som jag använder.

Medlem sedan maj 20012 812 inlägg
#12

Så länge du använder dig av UPDATE/INSERT/DELETE så kan du lägga ihop alla dessa eftersom dessa inte returnerar något värde.

Du kan även lägga ihop alla SELECT satser om du sedan använder en DataReader så kan man läsa de olika "recordseten" som du får tillbaka i denna datareader.

Om man har databsen på en annan dator än den dator som skall ha resultatet (vilket man oftast har) så skall man försöka minimera antalet frågor mot databasen, eftersom det oftas är nätverket som blir flaskhalsen, speciellt om det är många frågor och mycket data som skall skickas.

- M

Medlem sedan nov. 2003569 inlägg
#13

Ok, Alles gut :D

Medlem sedan nov. 2003569 inlägg
#14

Jag testade litegrann som du sa ang. att öppna och stänga efter varje fråga:

for(int x=0;x<1000;x++)
{
mycommand.Connection.Open();
mycommand.CommandText="INSERT INTO kunder (namn,telenr,adress,postnr,ort) VALUES ('namn','telenr','adress','postnr','ort')";
mycommand.ExecuteNonQuery();
mycommand.Connection.Close();
}

och så testade jag denna:

mycommand.Connection.Open();
for(int x=0;x<1000;x++)
{
mycommand.CommandText="INSERT INTO kunder (namn,telenr,adress,postnr,ort) VALUES ('namn','telenr','adress','postnr','ort')";
mycommand.ExecuteNonQuery();
}
mycommand.Connection.Close();

Och det visade sig att den nedre bara gjorde 626 poster i databasen, medans den övre gjorde det korrekta 1000 posterna. Det visar ganska tydligt att öppna och stänga efter varje fråga är en förutsättning för att det ska fungera överhuvudtaget. :bire

Medlem sedan maj 20012 812 inlägg
#15

Och det visade sig att den nedre bara gjorde 626 poster i databasen, medans den övre gjorde det korrekta 1000 posterna. Det visar ganska tydligt att öppna och stänga efter varje fråga är en förutsättning för att det ska fungera överhuvudtaget.

Då har du nog något annat problem, för båda två koder skall skriva in 1000 poster utan problem.

Medlem sedan nov. 2003569 inlägg
#16

access databasen kanske bara hade en dålig dag eller nåt. för nu funkade det med eller utan stänga och öppna. Men jag ska nog fortsättningsvis öppna och stänga efter varje fråga, känns tryggast så efter mitt förra test där den bara skrev 626 st, blev lite nojjig då ;)

277 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
128 ms — deklarationer (db)
0 ms — hämta statistik (cache)
147 ms — hämta tråd, inlägg och bilagor (db)
123 ms — ändringar (db)