Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comparaison des performances de SQL Server CE 4.0

À mon avis, il est incorrect de comparer la base de données intégrée (comme SQL CE) à la base de données relationnelle côté serveur (comme tout le reste, à l'exception de SQLite et de la version intégrée de Firebird).

La principale différence entre eux est que les bases de données relationnelles côté serveur à usage général (comme MS SQL, MySQL, Firebird Classic et SuperServer, etc.) sont installés en tant que service indépendant et s'exécutent en dehors de la portée de votre application principale . C'est pourquoi ils peuvent être beaucoup plus performants grâce à la prise en charge intrinsèque des architectures multicœurs et multiprocesseurs, en utilisant des fonctionnalités du système d'exploitation telles que la mise en cache préalable, VSS, etc. pour augmenter le débit en cas d'utilisation intensive de la base de données et peuvent réclamer autant de mémoire que possible. votre système d'exploitation peut fournir un seul service/application. Cela signifie également que leurs indicateurs de performance sont plus ou moins indépendants de votre application, mais dépendent largement de votre matériel. À cet égard, je dirais que les versions serveur de n'importe quelle base de données sont toujours plus performantes par rapport aux versions intégrées.

SQL CE (ainsi que Firebird Embedded, SQLite, TurboSQL et quelques autres) sont des moteurs de base de données intégrés , ce qui signifie que la base de données complète est regroupée dans un seul (ou au maximum 2) fichiers DLL qui sont distribués avec votre application. En raison des limitations de taille évidentes (aimeriez-vous avoir à distribuer une DLL de 30 Mo avec votre application de 2 à 3 Mo ?), ils s'exécutent également directement dans le contexte de votre application et la mémoire totale et les performances pour les opérations d'accès aux données sont partagées avec d'autres parties de votre application -- cela concerne à la fois la mémoire disponible, le temps CPU, le débit du disque, etc. L'exécution de threads gourmands en calculs en parallèle avec votre thread d'accès aux données peut entraîner une diminution considérable des performances de votre base de données.

En raison des différents domaines d'application, ces bases de données ont une palette d'options différente :server-db fournit une gestion étendue des utilisateurs et des droits, une prise en charge des vues et des procédures stockées, tandis que la base de données intégrée ne prend normalement pas en charge la gestion des utilisateurs et des droits et a une prise en charge limitée des vues. et les procédures stockées (ces dernières perdent la majorité de leurs avantages en s'exécutant côté serveur). Le débit de données est un goulot d'étranglement habituel du SGBDR, les versions de serveur sont généralement installées sur des volumes RAID par bandes, tandis que les bases de données intégrées sont souvent orientées mémoire (essayez de conserver toutes les données réelles dans la mémoire) et minimisez les opérations d'accès au stockage de données.

Donc, ce qui aurait probablement du sens est de comparer différents SGBDR embarqués pour .Net pour leurs performances, comme MS SQL CE 4.0, SQLite, Firebird Embedded, TurboSQL . Je ne m'attendrais pas à des différences drastiques pendant le fonctionnement habituel en dehors des heures de pointe, alors que certaines bases de données peuvent fournir un meilleur support pour les grands BLOB grâce à une meilleure intégration avec le système d'exploitation.

-- mettre à jour --

Je dois retirer mes derniers mots, car ma mise en œuvre rapide montre des résultats très intéressants.

J'ai écrit une courte application console pour tester les deux fournisseurs de données, voici le code source pour vous si vous voulez les expérimenter par vous-même.

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


    }
}

Clause de non-responsabilité nécessaire :

  1. J'ai obtenu ces résultats sur ma machine :Dell Precision WorkStation T7400 équipée de 2 processeurs Intel Xeon E5420 et de 8 Go de RAM, exécutant Win7 Enterprise 64 bits .
  2. J'ai utilisé les paramètres par défaut pour les deux bases de données avec la chaîne de connexion "Data Source=database_file_name".
  3. J'ai utilisé les dernières versions de SQL CE 4.0 et de SQLite/System.Data.SQLite (à partir d'aujourd'hui, le 3 juin 2011).

Voici les résultats pour deux échantillons différents :

> =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

... et un échantillon plus grand :

=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

Ainsi, comme vous pouvez le voir, toutes les opérations d'écriture (création, mise à jour, suppression) nécessitent presque 1000 fois plus de temps dans SQLite par rapport à SQLCE. Cela ne reflète pas nécessairement les mauvaises performances générales de cette base de données et peut être dû aux éléments suivants :

  1. Le fournisseur de données que j'utilise pour SQLite est System.Data.SQLite , c'est-à-dire un assemblage mixte contenant à la fois du code managé et non managé (SQLite est à l'origine entièrement écrit en C et la DLL ne fournit que des liaisons). P/Invoke et le marshaling des données consomment probablement une bonne partie du temps de fonctionnement.
  2. Il est fort probable que SQLCE 4.0 mette en cache toutes les données en mémoire par défaut, tandis que SQLite vide la plupart des modifications de données directement sur le stockage sur disque à chaque fois que la modification se produit. On peut fournir des centaines de paramètres pour les deux bases de données via une chaîne de connexion et les ajuster de manière appropriée.
  3. J'ai utilisé une série de requêtes uniques pour tester la base de données. Au moins SQLCE prend en charge les opérations en bloc via des classes .Net spéciales qui seraient mieux adaptées ici. Si SQLite les prend également en charge (désolé, je ne suis pas un expert ici et ma recherche rapide n'a rien donné de prometteur), ce serait bien de les comparer également.
  4. J'ai observé de nombreux problèmes avec SQLite sur des machines x64 (utilisant le même adaptateur .net) :de la fermeture inattendue de la connexion de données à la corruption du fichier de base de données. Je suppose qu'il y a des problèmes de stabilité avec l'adaptateur de données ou avec la bibliothèque elle-même.