webForumDet fria alternativet

Prestanda frågor

58 svar · 2 132 visningar · startad av thevice

theviceMedlem sedan dec. 2005198 inlägg
#1

Hej!

Jag har funderat lite på prestanda frågor när det gäller databas hantering och datan från databaser:

1. Vad går snabbast, använda SqlDataSource eller skriva databaskopplingen och allt själv i codebehind? SqlDataSource är ju mycket bekvämare. Då jag använder MySQL och SqlDatasource är ju inte gjort för MySQL men det kanske inte gör någon skillnad.

2. Känar man på att skriva ut resultaten man får av databasen direkt på .ASPX sidan eller att köra med ItemDataBound?

3. När jag försökte lära mig SqlDataSource så snubblade jag förbi något som hette i stil med SpeedyDataSource. Någon som har testat det och ger det någon skillnad prestanda mässigt?

4. Vad är det igentligen för skillnad på SqlDataSource och ObjectDataSource?

Tack på förhand!
/ Timmie

emissionMedlem sedan dec. 19996 721 inlägg
#2

thevice skrev:

1. Vad går snabbast, använda SqlDataSource eller skriva databaskopplingen och allt själv i codebehind? SqlDataSource är ju mycket bekvämare. Då jag använder MySQL och SqlDatasource är ju inte gjort för MySQL men det kanske inte gör någon skillnad.

Det går inte att svara på, eftersom vi inte vet hur bra datalager du skriver. Det finns dock alla möjligheter att göra en egen koppling snabbare, eftersom man kan undvika en massa overhead som DataSource sysslar med.

thevice skrev:

2. Känar man på att skriva ut resultaten man får av databasen direkt på .ASPX sidan eller att köra med ItemDataBound?

Det beror på... I ItemDataBound har man möjligheten att göra saker effektivare, i och med att man kan slippa kostsamma Bind och Eval. Fast man har förstås också alla möjligheter i världen att sabba till det med dålig kod.

thevice skrev:

3. När jag försökte lära mig SqlDataSource så snubblade jag förbi något som hette i stil med SpeedyDataSource. Någon som har testat det och ger det någon skillnad prestanda mässigt?

Aldrig hört talas om.

thevice skrev:

4. Vad är det igentligen för skillnad på SqlDataSource och ObjectDataSource?

SqlDataSource jobbar mot en SQL-databas, ObjectDataSource mot ett objektbaserat affärslager.

theviceMedlem sedan dec. 2005198 inlägg
#3

Tackar för de svaren. Jag antar att det jag skriver inte är speciellt svår skrivet så prestanda i mina fall gör nog ingen större skillnad förutom att det går snabbare för mig att använda SqlDataSource.

För något jag har märkt sen jag gick över till ASP.NET från ASP är att mina sidor laddar mycket segare. Jag vet inte om det är ASP.NET i helhet eller mina koder. Men på ett sätt så känns det ju som o SqlDataSource slöar ner lite eftersom det finns så mycket saker i det som jag inte behöver. Men de är väll sånt man får ta om man är lat. ;)

ArizonMedlem sedan juli 200799 inlägg
#4

Skriv en egen databashanteringsklass annars så slipper du allt onödigt skit...Du kan göra metoderna ganska generella. När jag gjorde ett asp.net-projekt i skolan med databas så skrev jag en databasklass till det. vi använde även stored procedures för all kontakt (vet inte om det är bästa sättet dock) så det gick att göra db-handlern ganska generell.

theviceMedlem sedan dec. 2005198 inlägg
#5

Tyvärr så har jag inte de kunskaperna för att kunna skriva en sådan. Jag har funderat på ett DAL men aldrig hittat någon artikel eller dylikt som jag förstår mig på.

ArizonMedlem sedan juli 200799 inlägg
#6

hypotetiskt:

du behöver en connectionmetod som skapar en connection med databasen.

du behöver en metod som anropar stored procedures och sedan returnerar dataset, alternativt som tar in en sql-string och returnerar ett dataset.

du behöver en metod som gör update/insert/delete. kan returnera int som status.

kolla på nätet om du kan hitta nåt.. jag har tyvärr inte tid. annars skulle jag kunnat gräva upp min klass.. dock är den tänkt för MS SQL Server. ska se om jag kan hitta den ikväll eller i helgen.

GladhMedlem sedan maj 20012 812 inlägg
#7

Jag kan dela med mig av en som jag skrivit, den är kanske lite overkill, men här kommer den.

Den består av 2 generella filer, ett interface och en basklass. Samt specifika filer för respektive databas som man anropar.

Här kommer interfacet:

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace TS.DataAccess
{
    public interface IDataAccess
    {
        object ExecuteScalar(string connectionString, IDbCommand command);
        int ExecuteNoResult(string connectionString, IDbCommand command);
        System.Data.DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command);
    }
}

Här kommer basklassen

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace TS.DataAccess
{
	public abstract class BaseDataAccess : IDataAccess
	{
		#region Abstract methods
		protected abstract int ExecuteNoResult(string connectionString, IDbCommand command);
        protected abstract object ExecuteScalar(string connectionString, IDbCommand command);
		protected abstract DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command);
		#endregion

		#region IDataAccess Members
        object IDataAccess.ExecuteScalar(string connectionString, IDbCommand command)
        {
            return ExecuteScalar(connectionString, command);
        }
		int IDataAccess.ExecuteNoResult(string connectionString, IDbCommand command)
		{
			return ExecuteNoResult(connectionString, command);
		}
		System.Data.DataTable IDataAccess.ExecuteDataTableResult(string connectionString, params IDbCommand[] command)
		{
			return ExecuteDataTableResult(connectionString, command);
		}
		#endregion
	}
}

Här kommer själva dataaccessklassen mot SQLServer.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace TS.DataAccess.SqlServer
{
	public class DataAccess : TS.DataAccess.BaseDataAccess
	{
		#region -- Private Methods throw interface
		protected override int ExecuteNoResult(string connectionString, IDbCommand command)
		{
			//-- Declaration
			int numberOfRowsAffected = 0;

			//-- Create ConnectionObject
			SqlConnection connection = new SqlConnection();
			connection.ConnectionString = connectionString;

			try
			{
				//-- Execute command
				command.Connection = connection;
				connection.Open();
				numberOfRowsAffected = command.ExecuteNonQuery();
			}
			finally
			{
				if (connection != null)
					connection.Dispose();
			}

			//-- Return numberofrows affected
			return numberOfRowsAffected;
		}
        protected override object ExecuteScalar(string connectionString, IDbCommand command)
        {
            //-- Declaration
            object result = null;

            //-- Create ConnectionObject
            SqlConnection connection = new SqlConnection();
            connection.ConnectionString = connectionString;

            try
            {
                //-- Execute command
                command.Connection = connection;
                connection.Open();
                result = command.ExecuteScalar();
            }
            finally
            {
                if (connection != null)
                    connection.Dispose();
            }

            //-- Return numberofrows affected
            return result;
        }
        protected override DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command)
		{

			//-- Declara variables
			SqlDataAdapter dataAdapter = null;
			DataTable dataTable = null;

			//-- Create ConnectionObject
			SqlConnection connection = new SqlConnection();
			connection.ConnectionString = connectionString;

			try
			{
				//-- Loop through all commands and execute, only return the last
				for (int i = 0; i < command.Length; i++)
				{
					//-- Create DataAdapter
					dataAdapter = new SqlDataAdapter();
					dataTable = new DataTable();
					//-- Set connection to command object
					command[i].Connection = connection;
					//-- Fill DataTable with data
					dataAdapter.SelectCommand = (SqlCommand)command[i];
					connection.Open();
					dataAdapter.Fill(dataTable);
				}
			}
			finally
			{
				//-- Clean up after us
				if (dataAdapter != null)
					dataAdapter.Dispose();
				if (connection != null)
					connection.Dispose();
			}
			//-- Return datatable
			return dataTable;
		}
		#endregion
	}
}

Om man tittar på basklassen så gör den egentligen inget, den finns där bara för att jag är lat och inte orkar implementera interfacet i varje ny databas som man skall anropa (samt att det ser rätt coolt ut ;))

Iprincip så behöver du bara själv dataaccess klassen, men jag skulle rekomendera dig att ta med interfacet och låta ditt program använda sig av det som instans istället, eftersom det blir så mycket enklare att byta databashanterar så fall om du måste göra det någon gång.

När du vill använda den så låter du ditt BL lager skapa ett IDBCommad objekt och skickar ner det till ditt DataAccesslager. Om du vill gör speciella metoder för typ Insert/Update/Select så läger du ett lager mellan ditt BL och detta DataAccessLager. Du du från ditt BL kallar till ditt nya DataLager som skapar ett IDBCommandObjekt som i sin tur kallar på DataAccessLagret. Ju mindre kod det finns i varje lager destu mer kan dessa lager återanvändas mellan olika projekt, men man måste skriva mer i respektive projektslager. Jag kan säga att detta DataAccessLager som jag har är ett lager som ligger under min ORMapper som i sin tur består av ett antal lager. Så ORMappern kallar på DataAccessLageret när den vill operera på en databas. Men jag skulle lika gärna anropa DataAccessLagret direkt från en ASP.NET sida om jag velat.

- M

theviceMedlem sedan dec. 2005198 inlägg
#8

Man får tacka för det, tyvärr är jag för dum eller bara har för lite kunskaper för att kunna förstå och använda det du har skrivit. Får ta en titt på det när jag har fått mer kunskaper eller om någon/du orkar beskriva lite enklare hur man använder det.

Innan jag märkte att SqlDataSource fungerar med MySQL så gjorde jag allt på det enklaste sättet:
using (conn)
{
using (command)
{
fill
}
}

Så ni kanske förstår att mina kunskaper inte är de största. Men jag antar att med Glads class så skulle allt gå mycket fortare och snabbare för mig att skriva?

NickemannenMedlem sedan aug. 20003 575 inlägg
#9

Gladh skrev:

Jag kan dela med mig av en som jag skrivit, den är kanske lite overkill, men här kommer den.

Den består av 2 generella filer, ett interface och en basklass. Samt specifika filer för respektive databas som man anropar.

Här kommer interfacet:

using System;
using System.Collections.Generic;
using System.Data;
using System.Text;


namespace TS.DataAccess
{
    public interface IDataAccess
    {
        object ExecuteScalar(string connectionString, IDbCommand command);
        int ExecuteNoResult(string connectionString, IDbCommand command);
        System.Data.DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command);
    }
}

Här kommer basklassen

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace TS.DataAccess
{
	public abstract class BaseDataAccess : IDataAccess
	{
		#region Abstract methods
		protected abstract int ExecuteNoResult(string connectionString, IDbCommand command);
        protected abstract object ExecuteScalar(string connectionString, IDbCommand command);
		protected abstract DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command);
		#endregion

		#region IDataAccess Members
        object IDataAccess.ExecuteScalar(string connectionString, IDbCommand command)
        {
            return ExecuteScalar(connectionString, command);
        }
		int IDataAccess.ExecuteNoResult(string connectionString, IDbCommand command)
		{
			return ExecuteNoResult(connectionString, command);
		}
		System.Data.DataTable IDataAccess.ExecuteDataTableResult(string connectionString, params IDbCommand[] command)
		{
			return ExecuteDataTableResult(connectionString, command);
		}
		#endregion
	}
}

Här kommer själva dataaccessklassen mot SQLServer.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace TS.DataAccess.SqlServer
{
	public class DataAccess : TS.DataAccess.BaseDataAccess
	{
		#region -- Private Methods throw interface
		protected override int ExecuteNoResult(string connectionString, IDbCommand command)
		{
			//-- Declaration
			int numberOfRowsAffected = 0;

			//-- Create ConnectionObject
			SqlConnection connection = new SqlConnection();
			connection.ConnectionString = connectionString;

			try
			{
				//-- Execute command
				command.Connection = connection;
				connection.Open();
				numberOfRowsAffected = command.ExecuteNonQuery();
			}
			finally
			{
				if (connection != null)
					connection.Dispose();
			}

			//-- Return numberofrows affected
			return numberOfRowsAffected;
		}
        protected override object ExecuteScalar(string connectionString, IDbCommand command)
        {
            //-- Declaration
            object result = null;

            //-- Create ConnectionObject
            SqlConnection connection = new SqlConnection();
            connection.ConnectionString = connectionString;

            try
            {
                //-- Execute command
                command.Connection = connection;
                connection.Open();
                result = command.ExecuteScalar();
            }
            finally
            {
                if (connection != null)
                    connection.Dispose();
            }

            //-- Return numberofrows affected
            return result;
        }
        protected override DataTable ExecuteDataTableResult(string connectionString, params IDbCommand[] command)
		{

			//-- Declara variables
			SqlDataAdapter dataAdapter = null;
			DataTable dataTable = null;

			//-- Create ConnectionObject
			SqlConnection connection = new SqlConnection();
			connection.ConnectionString = connectionString;

			try
			{
				//-- Loop through all commands and execute, only return the last
				for (int i = 0; i < command.Length; i++)
				{
					//-- Create DataAdapter
					dataAdapter = new SqlDataAdapter();
					dataTable = new DataTable();
					//-- Set connection to command object
					command[i].Connection = connection;
					//-- Fill DataTable with data
					dataAdapter.SelectCommand = (SqlCommand)command[i];
					connection.Open();
					dataAdapter.Fill(dataTable);
				}
			}
			finally
			{
				//-- Clean up after us
				if (dataAdapter != null)
					dataAdapter.Dispose();
				if (connection != null)
					connection.Dispose();
			}
			//-- Return datatable
			return dataTable;
		}
		#endregion
	}
}

Om man tittar på basklassen så gör den egentligen inget, den finns där bara för att jag är lat och inte orkar implementera interfacet i varje ny databas som man skall anropa (samt att det ser rätt coolt ut ;))

Iprincip så behöver du bara själv dataaccess klassen, men jag skulle rekomendera dig att ta med interfacet och låta ditt program använda sig av det som instans istället, eftersom det blir så mycket enklare att byta databashanterar så fall om du måste göra det någon gång.

När du vill använda den så låter du ditt BL lager skapa ett IDBCommad objekt och skickar ner det till ditt DataAccesslager. Om du vill gör speciella metoder för typ Insert/Update/Select så läger du ett lager mellan ditt BL och detta DataAccessLager. Du du från ditt BL kallar till ditt nya DataLager som skapar ett IDBCommandObjekt som i sin tur kallar på DataAccessLagret. Ju mindre kod det finns i varje lager destu mer kan dessa lager återanvändas mellan olika projekt, men man måste skriva mer i respektive projektslager. Jag kan säga att detta DataAccessLager som jag har är ett lager som ligger under min ORMapper som i sin tur består av ett antal lager. Så ORMappern kallar på DataAccessLageret när den vill operera på en databas. Men jag skulle lika gärna anropa DataAccessLagret direkt från en ASP.NET sida om jag velat.

- M

Varför gör du inte en assembly som klarar flera dbs och använder dig av en factory där du vid uppstart väljer vilken typ av dbs som skall användas så slipper du tänka på DataAccessLagret :).

DataAccessFactory är en statisk klass.

// Sätts vid uppstart.
DataAccessLayerFactory.DatabaseType = DatabaseType.MySql;
DataAccessLayerFactory.ConnectionString = "....";

// Detta är när en instans skall hämtas.
IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance();

Kör man ASP.NET kan ett tips vara att om det är en *.aspx sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger, för vad jag fattat det som så är det ofta i öppnandet och stängandet av databaskopplingen där en eventuell prestandaförlust ligger. Helst skall kanske kopplingen kapslas in av BL lagret som man kanske då lägger i Context.Items.
T.ex. när jag utvecklar med NHibernate lägger jag min NHibernatesessionen i Context.Items som jag har wrappat in.

Samtidigt tänkte jag pusha lite för NHibernate som jag tycker är grymt bra (y).
Dock kan prestandan vara något sämre vid uppstart av applikationen då dll:erna skall läsas in. Men vid en ASP.NET applikation så gör det ju i princip inget, för där startar ju ASP.NET applikationen bara en gång.

Jag tror man kan spara prestanda med NHibernate, eftersom man kanske lättare få en överblick av vad som händer och bara laddar viss data en gång iallfall om det handlar om WinForms.

emissionMedlem sedan dec. 19996 721 inlägg
#10

Nickemannen skrev:

DataAccessFactory är en statisk klass.

// Sätts vid uppstart.
DataAccessLayerFactory.DatabaseType = DatabaseType.MySql;
DataAccessLayerFactory.ConnectionString = "....";

// Detta är när en instans skall hämtas.
IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance();

Eller hellre


IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance(DatabaseType.MySql,"....");

..så att man inte skapar en race condition.

Nickemannen skrev:

Kör man ASP.NET kan ett tips vara att om det är en *.aspx sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger, för vad jag fattat det som så är det ofta i öppnandet och stängandet av databaskopplingen där en eventuell prestandaförlust ligger. Helst skall kanske kopplingen kapslas in av BL lagret som man kanske då lägger i Context.Items.

Ja, det är en mycket bekväm princip

GladhMedlem sedan maj 20012 812 inlägg
#11

Nickemannen skrev:

Varför gör du inte en assembly som klarar flera dbs och använder dig av en factory där du vid uppstart väljer vilken typ av dbs som skall användas så slipper du tänka på DataAccessLagret .

Jag har inte lagt den logiken i mitt DataAccessLager eftersom jag inte har haft något behov av det, men eftersom du använder dig av Interface både för DataAccessLagret och själv DBCommand som du skickar ner till DataAccessLagret så finns det inga problem att enkelt gör det du efterfrågar, jag har dock aldrig haft behovet.

Jag förslår dock emissons metod eftersom den är trådsäker och inte fuckar-up din applikation om du skulle behöva använda dig av olika databaser eller olika kopplingsträngar vilket ditt exempel skulle göra...

nickemannen skrev:

Kör man ASP.NET kan ett tips vara att om det är en *.aspx sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger, för vad jag fattat det som så är det ofta i öppnandet och stängandet av databaskopplingen där en eventuell prestandaförlust ligger. Helst skall kanske kopplingen kapslas in av BL lagret som man kanske då lägger i Context.Items.

Det är enligt mig en extremt dålig ide! För det är inte "öppnandet av databaskopplingar" som tar tid eftersom du oftas har kopplingar i din kopplingspool liggandes och väntandes. Om du däremot förbrukar de kopplingar som ligger där och sedan behöver en ny koppling så tar det tid, eftersom du då måste skapa/öppna en ny koppling och det tar tid, bra mycket mer än vad det tar att hämta en som redan ligger öppnad i kopplingspoolen. Så man skall alltid öppna databaskopplingen så sent som möjligt och stänga den så tidigt som möjligt, speciellt om du använder dig av typ ASPX sidor eftersom du inte har den blekaste anning om när din kod exekveras eftersom du inte kan styra trådhanteringen i IIS:en.

nickemannen skrev:

Jag tror man kan spara prestanda med NHibernate, eftersom man kanske lättare få en överblick av vad som händer och bara laddar viss data en gång iallfall om det handlar om WinForms.

Det har inget med NHibernate och göra ut mer hur du designar din applikation, jag kan också hämta "viss data" en gång om jag önskar det, det behöver jag ingen ORMapper för inte du heller ;)

Däremot håller jag med dig att ORMapper är något mycket bra när man utvecklar i större projekt eftersom man kan programmera mer OO rätt med en ORMapper istället för att skicka DataSet kors och tvärs...

- M

NickemannenMedlem sedan aug. 20003 575 inlägg
#12

Gladh skrev:

Nickemannen skrev:

Varför gör du inte en assembly som klarar flera dbs och använder dig av en factory där du vid uppstart väljer vilken typ av dbs som skall användas så slipper du tänka på DataAccessLagret .

Jag har inte lagt den logiken i mitt DataAccessLager eftersom jag inte har haft något behov av det, men eftersom du använder dig av Interface både för DataAccessLagret och själv DBCommand som du skickar ner till DataAccessLagret så finns det inga problem att enkelt gör det du efterfrågar, jag har dock aldrig haft behovet.

Sålänge man bara använder sig av en och samma databas så borde det väl inte vara några problem med en SessionFactory? Okej säg att den inte är statisk då? :) (har tagit mycket med detta från NHibernate när jag kapslat in den arkitekturen för att kunna byta ut den senare. Dock så körde jag inte static på den men tänkte att det kanske kvittade?

Vad är problemet med att om SessionFactory'n hade varit static? Efter att den är skapad är det ju bara read's som körs på den samt CreateSession() men den skapar ju bara nytt genom att läsa av inparametrarna. Samt att den inte skall öppna någon databasanslutning bara hålla på uppgifterna.

Gladh skrev:

nickemannen skrev:

Kör man ASP.NET kan ett tips vara att om det är en *.aspx sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger, för vad jag fattat det som så är det ofta i öppnandet och stängandet av databaskopplingen där en eventuell prestandaförlust ligger. Helst skall kanske kopplingen kapslas in av BL lagret som man kanske då lägger i Context.Items.

Det är enligt mig en extremt dålig ide! För det är inte "öppnandet av databaskopplingar" som tar tid eftersom du oftas har kopplingar i din kopplingspool liggandes och väntandes. Om du däremot förbrukar de kopplingar som ligger där och sedan behöver en ny koppling så tar det tid, eftersom du då måste skapa/öppna en ny koppling och det tar tid, bra mycket mer än vad det tar att hämta en som redan ligger öppnad i kopplingspoolen. Så man skall alltid öppna databaskopplingen så sent som möjligt och stänga den så tidigt som möjligt, speciellt om du använder dig av typ ASPX sidor eftersom du inte har den blekaste anning om när din kod exekveras eftersom du inte kan styra trådhanteringen i IIS:en.

Hmmm, här hänger jag inte riktigt med. Varför är det dåligt att lägga ett objekt i Context.Items? Jag har också läst att när det gäller webb så skall man öppna kopplingen så sent som möjligt samt stänga den så snabbt som möjligt efter att man kört allt det lärde jag mig när jag körde vanlig ASP för flera år sedan.
Men man kan köra som i Hibernate på den inkapslade funktionaliteten med session.Connect() och låta den vara disconnected från början.

Sedan om man lägger en session som öppnas i BeginRequest och som stänges i EndRequest så tror jag faktiskt inte att man förlorar så kraftigt mycket prestanda?

Det där med trådar, jo du kan ha en poäng där, man få se till att göra sitt bl/dataaccesslager trådsäkert :)

Gladh skrev:

nickemannen skrev:

Jag tror man kan spara prestanda med NHibernate, eftersom man kanske lättare få en överblick av vad som händer och bara laddar viss data en gång iallfall om det handlar om WinForms.

Det har inget med NHibernate och göra ut mer hur du designar din applikation, jag kan också hämta "viss data" en gång om jag önskar det, det behöver jag ingen ORMapper för inte du heller ;)

Däremot håller jag med dig att ORMapper är något mycket bra när man utvecklar i större projekt eftersom man kan programmera mer OO rätt med en ORMapper istället för att skicka DataSet kors och tvärs...

- M

Självklart har det hur man designar sin applikation, men jag gav det som tips bara.

Kul med sådana här diskussioner tycker jag (y)

PaceMedlem sedan juni 20019 024 inlägg
#13

Nickemannen skrev:

Kul med sådana här diskussioner tycker jag (y)

Instämmer. Just hur man ska bygga arkitekturen är bland det svåraste jag vet. Kräver mycket kunskap och erfarenhet och inget sätt är riktigt rätt. En djungel.

emissionMedlem sedan dec. 19996 721 inlägg
#14

Gladh skrev:

Det är enligt mig en extremt dålig ide! För det är inte "öppnandet av databaskopplingar" som tar tid eftersom du oftas har kopplingar i din kopplingspool liggandes och väntandes. Om du däremot förbrukar de kopplingar som ligger där och sedan behöver en ny koppling så tar det tid, eftersom du då måste skapa/öppna en ny koppling och det tar tid, bra mycket mer än vad det tar att hämta en som redan ligger öppnad i kopplingspoolen. Så man skall alltid öppna databaskopplingen så sent som möjligt och stänga den så tidigt som möjligt, speciellt om du använder dig av typ ASPX sidor eftersom du inte har den blekaste anning om när din kod exekveras eftersom du inte kan styra trådhanteringen i IIS:en.

Nä, det är inte den öppna kopplingen man lägger i Context.Items, utan en instans av "IDataAccessObject" eller vad man nu har. Hur man väljer att öppna och stänga kopplingar är en implementeringsfråga i denna klass.

theviceMedlem sedan dec. 2005198 inlägg
#15

Kul att ni kan diskutera om hur man ska bygga upp sin sida. Tyvärr så är allt grekiska för mig.

Det värsta är att jag inte vet vad det är som slöar ner min sida. Iof så kanske det kan vara att jag öppnar min databas koppling minst två gånger? Jag har byggt upp min sida på detta vis:
En basklass som är inkluderad på varje sida, denna basklass uppdaterar databasen i page_load. Sedan så hämtar jag olika slags data på mina andra sidor som har min basklass inkluderad. Kanske det som är felet?
Låt oss säga att jag ska göra en gästbok.

Först så uppdateras databasen med tid och kollar om det finns någon session i min basclass.
På gästboks sidan så hämtar jag alla inläggen. Inte mer än så.
Det blir alltså att öppna och stänga min databas två gånger, och att kolla om en session finns tar väll inte så pass mycket?

Hur kan jag göra för att få detta bättre om det är där felet ligger?

emissionMedlem sedan dec. 19996 721 inlägg
#16

Det du beskriver ska definitivt inte leda till något prestandaproblem. Du får försöka isolera vad det är som går långsamt.

GladhMedlem sedan maj 20012 812 inlägg
#17

Nickemannen skrev:

Vad är problemet med att om SessionFactory'n hade varit static?

Det är inget problem så länge du inte accessar propertys så som du visade exemplet där du satt en databas och sedan en kopplingsträng.

// Sätts vid uppstart.
DataAccessLayerFactory.DatabaseType = DatabaseType.MySql;
DataAccessLayerFactory.ConnectionString = "....";

// Detta är när en instans skall hämtas.
IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance();

Är inte trådsäker kod. Eftersom Det rent teoretisk skulle kunna finnas en annan sida som hade följande kod:

// Sätts vid uppstart.
DataAccessLayerFactory.DatabaseType = DatabaseType.Access;
DataAccessLayerFactory.ConnectionString = ",,,,,,,,,,";

// Detta är när en instans skall hämtas.
IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance();

Och först körs dina två propertygets från första kodsnutten, sedan skiftas trådarna och de 2 property gets i nedersta kodsnutten körs och sedan får första tråden köra sin CreateInstance() kod, vilken databas kommer nu översta kodsnutten vara kopplad mot? Just det mot en Accessdatabas med kopplingsträngen ",,,,,,".

nickemannen skrev:

Varför är det dåligt att lägga ett objekt i Context.Items?

Det är inte dåligt om jag missförstod dig, jag förstod dig dock som att detta objekt som du har lagt i context.Items håller en öppen koppling mot databasen, och det är dåligt. Om den inte håller en öppen koppling utan öppnar och stänger koppling vid varje anrop så är det inte dåligt att hålla objektet i context.Items

nickemannen skrev:

Sedan om man lägger en session som öppnas i BeginRequest och som stänges i EndRequest så tror jag faktiskt inte att man förlorar så kraftigt mycket prestanda?

Det beror på vad du menar med en session? Om du har en öppen koppling till din databas från BeginRequest till EndRequest och det är samma koppling, så är det en extremt dålig ide. Inte för låganvändar siter, men ur skalbarhetsynpunkt är det förödande att göra något sådant.

nickemannen skrev:

Det där med trådar, jo du kan ha en poäng där, man få se till att göra sitt bl/dataaccesslager trådsäkert

Japp, och det enklaste sättet är att inte använda statiska objekt/metoder, eller om man använder dem, inte accessa några variabler i samma klass utan för den egna metoden.

- M

GladhMedlem sedan maj 20012 812 inlägg
#18

emission skrev:

Nä, det är inte den öppna kopplingen man lägger i Context.Items, utan en instans av "IDataAccessObject" eller vad man nu har. Hur man väljer att öppna och stänga kopplingar är en implementeringsfråga i denna klass.

Vad är det då du vinner i prestanda med följande formulering: sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger?

- M

NickemannenMedlem sedan aug. 20003 575 inlägg
#19

Gladh skrev:

emission skrev:

Nä, det är inte den öppna kopplingen man lägger i Context.Items, utan en instans av "IDataAccessObject" eller vad man nu har. Hur man väljer att öppna och stänga kopplingar är en implementeringsfråga i denna klass.

Vad är det då du vinner i prestanda med följande formulering: sida som anropas lägga en IDataAccessObject i Context.Items för att inte behöva skapa/öppna/databaskopplingen för många gånger?

- M

Vi var nog inte ute efter prestandan utan mer att det var ett tips att lägga den där för att slippa implemmentera det på varje sida. Och desto mindre kod desto lättare är det att hålla reda på allting. Så indirekt kan det leda till prestandaminskningar även om det inte gör det direkt

// Sätts vid uppstart.
DataAccessLayerFactory.DatabaseType = DatabaseType.MySql;
DataAccessLayerFactory.ConnectionString = "....";

// Detta är när en instans skall hämtas.
IDataAccessObject dataAccessObject = DataAccessLayer.CreateInstance();

Jaha men då har jag rätt ändå, meingen var att DataAccessLayerFactory bara skall köras under uppstart som jag skrev i kommentaren. Och uppstarten av en .NET applikation körs väl bara en gång och inte varje gång en aspx sida anropas.
Jag kanske inte var tillräckligt tydlig.
t.ex. NHibernate scannar ju av en eller flera assemblies och det vill man ju inte göra varje gång en aspx sida anropas utan bara en gång och då läggs det lämpligtsvis i en factory.

NickemannenMedlem sedan aug. 20003 575 inlägg
#20

thevice skrev:

Kul att ni kan diskutera om hur man ska bygga upp sin sida. Tyvärr så är allt grekiska för mig.

Det värsta är att jag inte vet vad det är som slöar ner min sida. Iof så kanske det kan vara att jag öppnar min databas koppling minst två gånger? Jag har byggt upp min sida på detta vis:
En basklass som är inkluderad på varje sida, denna basklass uppdaterar databasen i page_load. Sedan så hämtar jag olika slags data på mina andra sidor som har min basklass inkluderad. Kanske det som är felet?
Låt oss säga att jag ska göra en gästbok.

Först så uppdateras databasen med tid och kollar om det finns någon session i min basclass.
På gästboks sidan så hämtar jag alla inläggen. Inte mer än så.
Det blir alltså att öppna och stänga min databas två gånger, och att kolla om en session finns tar väll inte så pass mycket?

Hur kan jag göra för att få detta bättre om det är där felet ligger?

Du har inte lite kod, och en adress till sidan där den körs online som du kan visa oss så blir det kanske lite lättare.

149 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
146 ms — hämta tråd, inlägg och bilagor (db)