Linq, Dataset, Recordset performance resultat

Jeg har i længere tid undret mig over en dårlig performance med anvendelse af LINQ, og nu er jeg gået på jagt efter synderen i tiden i databasen SQL Server.

I denne første test jeg har lavet har jeg dog ikke fundet synderen, men stadig et interessant resultat, som bekræfter mig i, at du ikke skal bruge et Dataset som bliver indlæst med data fra en SqlDataAdapter med Fill metoden, og her kan du se hvorfor:

 

 

Min test går i sin simpelhed ud på at læse 1.000, 10.000 og 100.000 rækker fra en simpel tabel og så måle, hvor lang tid det tager få de tre måder at hente data ud på fra en SQL Server.

Konklusion

Recordset dobbelt så hurtigt til små database kørsler

Ved små data mængder er LINQ ikke så hurtig som Recordset, men da tiden er så lav mærkes det ikke, hvis de er enkelte jobs, så det er reelt kun et problem, hvis du skal køre rigtig mange af disse små-jobs mod databasen så husk du er færdig på den halve tid med et Recordset.

Dataset skal anvendes, hvor mange af de samme data skal anvendes alsidsigt

Når der skal tælles, hvor mange rækker man har fået ud i et resultat, så må du bede til, at du ikke har anvendt Dataset metoden, det der trækker ned er helt klart at måden hvorpå man skal hive data ud for at få et Dataset ikke egner sig til små resultater, fordi man skal hente hele tabellen med en hel vildt masse egenskaber ud, og det tager bare tid.

Med 10.000 rækker er både LINQ og Recordset over dobbelt så hurtige som Dataset.

Når vi øger antallet af rækker med en faktor 10 til 10.000 rækker stiger test tiderne selvfølgelig, fordi databasen tager længere tid om at sende 10 gange så meget data, men overraskende meget synes jeg. LINQ metoden stiger med en faktor 4,5, Dataset metoden stiger med en faktor 10 og Recordset metoden stiger med en faktor 6,5.

Med 100.000 rækker begynder LINQ at hale gevaldigt ind på Recordset.

Når vi øver antallet af rækker yderligere med en faktor 10 til 100.000 rækker, ville jeg forvente samme stigningsgrad som før med fra 1.000 til 10.000, men nu stiger den endnu mere. LINQ metoden stiger med en faktor 8,7, Dataset metoden med en faktor 9 og Recordset metoden med en faktor 9,5.

Download Visual Studio 2008 Projektet

Testsystem

Hardware: Bærbar HP Elitebook, 3GB RAM, 2,53GHz Intel Core Duo, 32bit
Software: Windows 7 32bit, SQL Server Express 2009, Visual Studio 2008 Professional Developer Web Server

Testforløb

Jeg har opdelt min test i 4 forløb og hver eneste forløb er kørt 10 gange på samme metode for så til sidst at få en gennemsnits tidsforbrug som toneangivende konklusion.

LINQ måling metode

private void DoLinqTest()
{
    DateTime dtLinqStart = DateTime.Now;
    using ( DB.dbDataContext db = new DB.dbDataContext() )
    {
        // Execution code
    }
    DateTime dtLinqEnd = DateTime.Now;
    lblLinqTime.Text = ( dtLinqEnd - dtLinqStart ).ToString();
}

Dataset måling metode

private void DoDataSetTest()
{
    DateTime dtDsStart = DateTime.Now;
    using ( SqlConnection dbCon = new SqlConnection( ConfigurationManager.ConnectionStrings[ "dbConnectionString" ].ConnectionString ) )
    {
        using ( SqlDataAdapter sqlAdap = new SqlDataAdapter( "SELECT * FROM item", dbCon ) )
        {
            DataSet ds = new DataSet();
            sqlAdap.Fill( ds );

            // Executing code
        }
    }
    DateTime dtDsEnd = DateTime.Now;
    lblDsTime.Text = ( dtDsEnd - dtDsStart ).ToString();
}

Recordset måling metode

private void DoRecordSetTest()
{
    DateTime dtRsStart = DateTime.Now;
    using ( SqlConnection dbCon = new SqlConnection( ConfigurationManager.ConnectionStrings[ "dbConnectionString" ].ConnectionString ) )
    {
        dbCon.Open();
        using ( SqlCommand sqlCmd = new SqlCommand( "SELECT * FROM item", dbCon ) )
        {
            using ( SqlDataReader rs = sqlCmd.ExecuteReader() )
            {
                // Executing code
            }
        }
    }

    DateTime dtRsEnd = DateTime.Now;
    lblRsTime.Text = ( dtRsEnd - dtRsStart ).ToString();
}

1. forløb

En test som ses i Testresultat Sheet: 1000 List på at få 1000 database rækker ud som objekter af flg. type:

public class item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }

    public item()
    {
    }

}

Executing LINQ code:

List<item> objItems = ( from itm in db.items
                        select new item
                        {
                          Id = itm.id,
                          Name = itm.name,
                          Description = itm.description,
                          Date = itm.date.Value
                        } ).ToList();

Executing Dataset code:

List<item> items = new List<item>();
DataRow[] drs = ds.Tables[ 0 ].Select();
for ( int i = 0; i < drs.Length; i++ )
{
    object[] dbFields = drs[ i ].ItemArray;
    item itm = new item();
    itm.Id = ( int )dbFields[ 0 ];
    itm.Name = dbFields[ 1 ].ToString();
    itm.Description = dbFields[ 2 ].ToString();
    itm.Date = ( DateTime )dbFields[ 3 ];
    items.Add( itm );
}

Executing Recordset code:

List<item> items = new List<item>();
while ( rs.Read() )
{
  item itm = new item();
  itm.Id = rs.GetInt32( 0 );
  itm.Name = rs.GetString( 1 );
  itm.Description = rs.GetString( 2 );
  itm.Date = rs.GetDateTime( 3 );
  items.Add( itm );
}

2. forløb

En test som ses i Testresultat sheet: 1000 Count på at få antallet af rækker ud på en database tabel med 1.000 rækker

Executing LINQ code:

int count = ( from itm in db.items
              select new item
              {
                Id = itm.id,
                Name = itm.name,
                Description = itm.description,
                Date = itm.date.Value
              } ).Count();

Executing Dataset code:

int count = ds.Tables[ 0 ].Rows.Count;

Executing Recordset code:

int count = 0;
while ( rs.Read() )
{
    count++;
}

3. forløb

En test som ses i Testresultat sheet: 10000 List med samme Executing code som 1. forløb, men denne gang på at få 10.000 database rækker ud.

4. forløb

En test som ses i Testresultat sheet: 100000 List med samme Executing code som 1. forløb, men denne gang på at få 100.000 database rækker ud.

Testresultat

Download Visual Studio 2008 Projektet

, , , ,

En Kommentar

Skriv et svar

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>