sql >> Databasteknik >  >> RDS >> Sqlserver

Prestandajämförelse för SQL Server CE 4.0

Enligt min åsikt är det felaktigt att jämföra den inbäddade databasen (som SQL CE) med relationsdatabasen på serversidan (som alla andra, förutom SQLite och den inbäddade versionen av Firebird).

Den största skillnaden mellan dem är att de allmänna relationsdatabaserna på serversidan (som MS SQL, MySQL, Firebird Classic och SuperServer etc.) installeras som en oberoende tjänst och körs utanför ramen för din huvudapplikation . Det är därför de kan prestera mycket bättre på grund av det inneboende stödet för multi-core och multi-CPU-arkitekturer, använder OS-funktioner som pre-caching, VSS etc för att öka genomströmningen vid intensiv databasdrift och kan göra anspråk på så mycket minne som ditt operativsystem kan tillhandahålla en enda tjänst/applikation. Det betyder också att prestandaindikatorerna för dem är mer eller mindre oberoende av din applikation, men till stor del beror på din hårdvara. I detta avseende skulle jag säga att serverversionerna av alla databaser alltid presterar bättre än de inbäddade.

SQL CE (tillsammans med Firebird Embedded, SQLite, TurboSQL och några andra) är inbäddade DB-motorer , vilket innebär att hela databasen är packad i en enda (eller maximalt 2) DLL-filer som distribueras tillsammans med din applikation. På grund av de uppenbara storleksbegränsningarna (skulle du vilja behöva distribuera en 30 MB DLL tillsammans med din 2-3 MB långa applikation?) kör de också direkt i din applikation och det totala minnet och prestandan för dataåtkomstoperationer delas med andra delar av din applikation -- det gäller både tillgängligt minne, CPU-tid, diskgenomströmning etc. Att ha en beräkningskrävande tråd som körs parallellt med din dataåtkomsttråd kan leda till en dramatisk minskning av din databasprestanda.

På grund av de olika användningsområdena har dessa databaser olika palett av alternativ:server-db ger omfattande användar- och rättighetshantering, stöd för vyer och lagrade procedurer, medan den inbäddade databasen normalt saknar stöd för användare och rättighetshantering och har begränsat stöd för vyer och lagrade procedurer (de sistnämnda förlorar majoriteten av sina fördelar med att köra på serversidan). Datagenomströmning är en vanlig flaskhals av RDBMS, serverversioner installeras vanligtvis på randiga RAID-volymer, medan inbäddade DB ofta är minnesorienterade (försök att behålla alla faktiska data i minnet) och minimera åtkomståtgärderna för datalagring.

Så, det som förmodligen skulle vara vettigt är att jämföra olika inbäddade RDBMS för .Net för deras prestanda, som MS SQL CE 4.0, SQLite, Firebird Embedded, TurboSQL . Jag skulle inte förvänta mig drastiska skillnader under normal drift utan topp, medan vissa databaser kan ge bättre stöd för stora BLOBs på grund av bättre integration med OS.

-- uppdatera --

Jag måste ta tillbaka mina sista ord, för min snabba implementering visar mycket intressanta resultat.

Jag skrev en kort konsolapplikation för att testa båda dataleverantörerna, här är källkoden för dig om du vill experimentera med dem på egen hand.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SQLite;
using System.Data.SqlServerCe;
using System.Data.Common;

namespace TestSQL
{
    class Program
    {
        const int NUMBER_OF_TESTS = 1000;

        private static string create_table;

        private static string create_table_sqlce =  "CREATE TABLE Test ( id integer not null identity primary key, textdata nvarchar(500));";
        private static string create_table_sqlite = "CREATE TABLE Test ( id integer not null primary key, textdata nvarchar(500));";

        private static string drop_table = "DROP TABLE Test";
        private static string insert_data = "INSERT INTO Test (textdata) VALUES ('{0}');";
        private static string read_data = "SELECT textdata FROM Test WHERE id = {0}";
        private static string update_data = "UPDATE Test SET textdata = '{1}' WHERE id = {0}";
        private static string delete_data = "DELETE FROM Test WHERE id = {0}";

        static Action<DbConnection> ACreateTable = (a) => CreateTable(a);
        static Action<DbConnection> ATestWrite = (a) => TestWrite(a, NUMBER_OF_TESTS);
        static Action<DbConnection> ATestRead = (a) => TestRead(a, NUMBER_OF_TESTS);
        static Action<DbConnection> ATestUpdate = (a) => TestUpdate(a, NUMBER_OF_TESTS);
        static Action<DbConnection> ATestDelete = (a) => TestDelete(a, NUMBER_OF_TESTS);
        static Action<DbConnection> ADropTable = (a) => DropTable(a);

        static Func<Action<DbConnection>,DbConnection, TimeSpan> MeasureExecTime = (a,b) => { var start = DateTime.Now; a(b); var finish = DateTime.Now; return finish - start; };

        static Action<string, TimeSpan> AMeasureAndOutput = (a, b) => Console.WriteLine(a, b.TotalMilliseconds);

        static void Main(string[] args)
        {
            // opening databases
            SQLiteConnection.CreateFile("sqlite.db");
            SQLiteConnection sqliteconnect = new SQLiteConnection("Data Source=sqlite.db");
            SqlCeConnection sqlceconnect = new SqlCeConnection("Data Source=sqlce.sdf");

            sqlceconnect.Open();
            sqliteconnect.Open();

            Console.WriteLine("=Testing CRUD performance of embedded DBs=");
            Console.WriteLine(" => Samplesize: {0}", NUMBER_OF_TESTS);

            create_table = create_table_sqlite;
            Console.WriteLine("==Testing SQLite==");
            DoMeasures(sqliteconnect);

            create_table = create_table_sqlce;
            Console.WriteLine("==Testing SQL CE 4.0==");
            DoMeasures(sqlceconnect);



            Console.ReadKey();

        }

        static void DoMeasures(DbConnection con)
        {
            AMeasureAndOutput("Creating table: {0} ms", MeasureExecTime(ACreateTable, con));
            AMeasureAndOutput("Writing data: {0} ms", MeasureExecTime(ATestWrite, con));
            AMeasureAndOutput("Updating data: {0} ms", MeasureExecTime(ATestUpdate, con));
            AMeasureAndOutput("Reading data: {0} ms", MeasureExecTime(ATestRead, con));
            AMeasureAndOutput("Deleting data: {0} ms", MeasureExecTime(ATestDelete, con));
            AMeasureAndOutput("Dropping table: {0} ms", MeasureExecTime(ADropTable, con));
        }



        static void CreateTable(DbConnection con)
        {
            var sqlcmd = con.CreateCommand();
            sqlcmd.CommandText = create_table;
            sqlcmd.ExecuteNonQuery();
        }

        static void TestWrite(DbConnection con, int num)
        {
            for (; num-- > 0; )
            {
                var sqlcmd = con.CreateCommand();
                sqlcmd.CommandText = string.Format(insert_data,Guid.NewGuid().ToString());
                sqlcmd.ExecuteNonQuery();
            }

        }

        static void TestRead(DbConnection con, int num)
        {
            Random rnd = new Random(DateTime.Now.Millisecond);
            for (var max = num; max-- > 0; )
            {
                var sqlcmd = con.CreateCommand();
                sqlcmd.CommandText = string.Format(read_data, rnd.Next(1,num-1));
                sqlcmd.ExecuteNonQuery();
            }
        }

        static void TestUpdate(DbConnection con, int num)
        {
            Random rnd = new Random(DateTime.Now.Millisecond);
            for (var max = num; max-- > 0; )
            {
                var sqlcmd = con.CreateCommand();
                sqlcmd.CommandText = string.Format(update_data, rnd.Next(1, num - 1), Guid.NewGuid().ToString());
                sqlcmd.ExecuteNonQuery();
            }
        }

        static void TestDelete(DbConnection con, int num)
        {
            Random rnd = new Random(DateTime.Now.Millisecond);
            var order = Enumerable.Range(1, num).ToArray<int>();
            Action<int[], int, int> swap = (arr, a, b) => { int c = arr[a]; arr[a] = arr[b]; arr[b] = c; };

            // shuffling the array
            for (var max=num; max-- > 0; ) swap(order, rnd.Next(0, num - 1), rnd.Next(0, num - 1));


            foreach(int index in order)
            {
                var sqlcmd = con.CreateCommand();
                sqlcmd.CommandText = string.Format(delete_data, index);
                sqlcmd.ExecuteNonQuery();
            }
        }

        static void DropTable(DbConnection con)
        {
            var sqlcmd = con.CreateCommand();
            sqlcmd.CommandText = drop_table;
            sqlcmd.ExecuteNonQuery();
        }


    }
}
 

Nödvändig ansvarsfriskrivning:

  1. Jag fick dessa resultat på min dator:Dell Precision WorkStation T7400 utrustad med 2 Intel Xeon E5420-processorer och 8 GB RAM, med 64bit Win7 Enterprise .
  2. Jag använde standardinställningarna för båda databaserna med anslutningssträngen "Datakälla=databasfilnamn".
  3. Jag använde de senaste versionerna av både SQL CE 4.0 och SQLite/System.Data.SQLite (från och med idag, 3 juni 2011).

Här är resultaten för två olika prover:

> =Testar CRUD-prestanda för inbäddade DBs=> => Samplestorlek:200> ==Testar SQLite==> Skapar tabell:396.0396 ms> Skriver data:22189.2187 ms> Uppdaterar data:23591.3589 ms> Läser data:1.2 ms> Läser data:1.2 ms. Raderar data:20963.0961 ms> Släpptabell:85.0085 ms> ==Testar SQL CE 4.0==> Skapar tabell:16.0016 ms> Skriver data:25.0025 ms> Uppdaterar data:56.0056 ms:80 ms läser:5056 ms:80 ms> Läser data:5056 ms:80 ms.> Dropping table:11.0011 ms

... och ett större urval:

 =Testning av CRUD -prestanda för inbäddad dbs ==> ProverSIZE:1000 ==Testning SQLite ==Skapa tabell:93.0093 MSWriting -data:116632.6621 MSUPDATATION DATA:104967.4957 MSREADING DATA:134.0134 MSDELETING DATA:10766.76.766 MSOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPning SQL CE 4.0==Skapar tabell:16.0016 msSkrivdata:128.0128 msUppdaterar data:307.0307 msLäsdata:164.0164 msTar bort data:306.0306 msSläpptabell:0133 ms. 

Så, som du kan se, kräver alla skrivoperationer (skapa, uppdatera, ta bort) nästan 1000 gånger mer tid i SQLite jämfört med SQLCE. Det återspeglar inte nödvändigtvis den allmänna dåliga prestandan för denna databas och kan bero på följande:

  1. Dataleverantören jag använder för SQLite är System.Data.SQLite , det vill säga en blandad sammansättning som innehåller både hanterad och ohanterad kod (SQLite är ursprungligen skriven helt i C och DLL tillhandahåller bara bindningar). Förmodligen äter P/Invoke och datamarshaking upp en bra bit av operationstiden.
  2. Mest troligt cachar SQLCE 4.0 all data i minnet som standard, medan SQLite rensar de flesta dataändringarna direkt till disklagringen varje gång förändringen sker. Man kan tillhandahålla hundratals parametrar för båda databaserna via anslutningssträng och justera dem på lämpligt sätt.
  3. Jag använde en serie enstaka frågor för att testa DB. Åtminstone SQLCE stöder bulkoperationer via speciella .Net-klasser som skulle passa bättre här. Om SQLite stöder dem också (tyvärr, jag är ingen expert här och min snabba sökning gav inget lovande) skulle det vara trevligt att jämföra dem också.
  4. Jag har observerat många problem med SQLite på x64-datorer (med samma .net-adapter):från att dataanslutningen stängdes oväntat till att databasfilen skadades. Jag antar att det finns vissa stabilitetsproblem antingen med dataadaptern eller med själva biblioteket.


  1. SQL Server vs. NoSQL

  2. Hur tar man backup av en enda tabell i en MySQL-databas?

  3. två främmande nycklar, hur man kartlägger med laravel vältalig

  4. Dålig praxis i databasdesign