sql >> Database >  >> RDS >> Sqlserver

Prestatievergelijking van SQL Server CE 4.0

Naar mijn mening is het onjuist om de embedded database (zoals SQL CE) te vergelijken met de relationele database aan de serverzijde (zoals de rest, behalve SQLite en de Embedded-versie van Firebird).

Het belangrijkste verschil tussen beide is dat de algemene server-side relationele databases (zoals MS SQL, MySQL, Firebird Classic en SuperServer enz.) worden geïnstalleerd als een onafhankelijke service en buiten het bereik van uw hoofdtoepassing . Dat is de reden waarom ze veel beter kunnen presteren vanwege de intrinsieke ondersteuning voor multi-core en multi-CPU-architecturen, gebruikmakend van OS-functies zoals pre-caching, VSS enz. uw besturingssysteem kan voorzien in een enkele service/toepassing. Het betekent ook dat de prestatie-indicatoren voor hen min of meer onafhankelijk zijn van uw toepassing, maar grotendeels afhankelijk zijn van uw hardware. In dit opzicht zou ik zeggen dat de serverversies van elke database altijd beter presteren in vergelijking met de ingebedde versies.

SQL CE (samen met Firebird Embedded, SQLite, TurboSQL en enkele andere) zijn embedded DB-engines , wat betekent dat de volledige database is verpakt in een enkele (of maximaal 2) DLL-bestanden die samen met uw applicatie worden gedistribueerd. Vanwege de duidelijke groottebeperkingen (zou u een 30 MB DLL willen distribueren samen met uw 2-3 MB lange applicatie?) Ze draaien ook direct in de context van uw applicatie en het totale geheugen en de prestaties voor gegevenstoegangsbewerkingen worden gedeeld met andere delen van uw applicatie -- dat betreft zowel beschikbaar geheugen, CPU-tijd, schijfdoorvoer, enz. Het hebben van rekenintensieve threads die parallel lopen met uw thread voor gegevenstoegang, kan leiden tot een dramatische afname van uw databaseprestaties.

Vanwege de verschillende toepassingsgebieden hebben deze databases verschillende opties:server-db biedt uitgebreid gebruikers- en rechtenbeheer, ondersteuning voor views en opgeslagen procedures, terwijl embedded database normaal gesproken geen ondersteuning heeft voor gebruikers- en rechtenbeheer en beperkte ondersteuning voor views en opgeslagen procedures (de laatste verliezen de meeste voordelen van het draaien aan de serverzijde). Gegevensdoorvoer is een gebruikelijk knelpunt van RDBMS, serverversies worden meestal geïnstalleerd op striped RAID-volumes, terwijl embedded DB vaak geheugengericht is (probeer alle daadwerkelijke gegevens in het geheugen te houden) en minimaliseert de toegang tot gegevensopslag.

Dus, wat waarschijnlijk logisch zou zijn, is om verschillende embedded RDBMS voor .Net te vergelijken voor hun prestaties, zoals MS SQL CE 4.0, SQLite, Firebird Embedded, TurboSQL . Ik zou geen drastische verschillen verwachten tijdens normale daluren, terwijl sommige databases mogelijk betere ondersteuning bieden voor grote BLOB's vanwege een betere integratie met het besturingssysteem.

-- bijwerken --

Ik moet mijn laatste woorden terugnemen, want mijn snelle implementatie laat zeer interessante resultaten zien.

Ik heb een korte consoletoepassing geschreven om beide gegevensproviders te testen. Hier is de broncode voor u als u er zelf mee wilt experimenteren.

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();
        }


    }
}

Noodzakelijke disclaimer:

  1. Ik kreeg deze resultaten op mijn computer:Dell Precision WorkStation T7400 uitgerust met 2 Intel Xeon E5420 CPU's en 8 GB RAM, met 64-bits Win7 Enterprise .
  2. Ik heb de standaardinstellingen voor beide DB's gebruikt met verbindingsreeks "Data Source=database_file_name".
  3. Ik heb de nieuwste versies van zowel SQL CE 4.0 als SQLite/System.Data.SQLite gebruikt (vanaf vandaag, 3 juni 2011).

Hier zijn de resultaten voor twee verschillende monsters:

> =Testing CRUD performance of embedded DBs=  
> => Samplesize: 200
> ==Testing SQLite== 
> Creating table: 396.0396 ms 
> Writing data: 22189.2187 ms 
> Updating data: 23591.3589 ms
> Reading data: 21.0021 ms 
> Deleting data: 20963.0961 ms 
> Dropping table: 85.0085 ms

> ==Testing SQL CE 4.0== 
> Creating table: 16.0016 ms 
> Writing data: 25.0025 ms 
> Updating data: 56.0056 ms 
> Reading data: 28.0028 ms 
> Deleting data: 53.0053 ms 
> Dropping table: 11.0011 ms

... en een grotere steekproef:

=Testing CRUD performance of embedded DBs=
 => Samplesize: 1000
==Testing SQLite==
Creating table: 93.0093 ms
Writing data: 116632.6621 ms
Updating data: 104967.4957 ms
Reading data: 134.0134 ms
Deleting data: 107666.7656 ms
Dropping table: 83.0083 ms

==Testing SQL CE 4.0==
Creating table: 16.0016 ms
Writing data: 128.0128 ms
Updating data: 307.0307 ms
Reading data: 164.0164 ms
Deleting data: 306.0306 ms
Dropping table: 13.0013 ms

Dus, zoals je kunt zien, vereisen alle schrijfbewerkingen (maken, bijwerken, verwijderen) bijna 1000x meer tijd in SQLite in vergelijking met SQLCE. Het weerspiegelt niet noodzakelijk de algemene slechte prestaties van deze database en kan te wijten zijn aan het volgende:

  1. De gegevensprovider die ik gebruik voor SQLite is de System.Data.SQLite , dat is een gemengde assembly die zowel beheerde als onbeheerde code bevat (SQLite is oorspronkelijk volledig in C geschreven en de DLL biedt alleen bindingen). Waarschijnlijk vreten P/Invoke en data-marshaling een groot deel van de operatietijd op.
  2. Hoogstwaarschijnlijk slaat SQLCE 4.0 standaard alle gegevens in het geheugen op, terwijl SQLite de meeste gegevenswijzigingen direct naar de schijfopslag spoelt telkens wanneer de wijziging plaatsvindt. Men kan honderden parameters voor beide databases aanleveren via een verbindingsreeks en ze op de juiste manier afstemmen.
  3. Ik heb een reeks enkele query's gebruikt om de DB te testen. SQLCE ondersteunt in ieder geval bulkbewerkingen via speciale .Net-klassen die hier beter geschikt zouden zijn. Als SQLite ze ook ondersteunt (sorry, ik ben hier geen expert en mijn snelle zoektocht leverde niets veelbelovends op), zou het leuk zijn om ze ook te vergelijken.
  4. Ik heb veel problemen waargenomen met SQLite op x64-machines (met dezelfde .net-adapter):van het onverwacht sluiten van een gegevensverbinding tot corruptie van databasebestanden. Ik neem aan dat er wat stabiliteitsproblemen zijn met de data-adapter of met de bibliotheek zelf.


  1. SQL Server 2005 / 2008 - meerdere bestandsgroepen?

  2. Hoe SQL Developer op een Mac te installeren

  3. AutoCount Records bij weergave

  4. Koppelingen verwijderen uit berichten in wordpress met behulp van query