SQL Server CE 4.0 performance comparison

前端 未结 4 1401
轮回少年
轮回少年 2020-12-04 10:17

SQL Server CE 4 (SQL Server Compact Edition 4.0) is not news already (If it is, you could read this article)

But it is very interesting to see SQL Server CE 4 perf

4条回答
  •  爱一瞬间的悲伤
    2020-12-04 10:43

    Because I'm having a real hard time with Alaudo's tests, test results, and ultimately with his conclusion, I went ahead and played around a bit with his program and came up with a modified version.

    It tests each of the following 10 times and outputs the average times:

    • sqlite without transactions, using default jounal_mode
    • sqlite with transactions, using default journal_mode
    • sqlite without transactions, using WAL jounal_mode
    • sqlite with transactions, using WAL journal_mode
    • sqlce without transactions
    • sqlce with transactions

    Here is the program (it's a class actually):

    using System;
    using System.Collections.Generic;
    using System.Data.Common;
    using System.Data.SqlServerCe;
    using System.Data.SQLite;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    
    class SqliteAndSqlceSpeedTesting
    {
        class Results
        {
            public string test_details;
            public long create_table_time, insert_time, update_time, select_time, delete_time, drop_table_time;
        }
    
        enum DbType { Sqlite, Sqlce };
    
        const int NUMBER_OF_TESTS = 200;
        const string create_table_sqlite = "CREATE TABLE Test (id integer not null primary key, textdata nvarchar(500));";
        const string create_table_sqlce = "CREATE TABLE Test (id integer not null identity primary key, textdata nvarchar(500));";
        const string drop_table = "DROP TABLE Test";
        const string insert_data = "INSERT INTO Test (textdata) VALUES ('{0}');";
        const string read_data = "SELECT textdata FROM Test WHERE id = {0}";
        const string update_data = "UPDATE Test SET textdata = '{1}' WHERE id = {0}";
        const string delete_data = "DELETE FROM Test WHERE id = {0}";
    
        public static void RunTests()
        {
            List results_list = new List();
    
            for (int i = 0; i < 10; i++) {
                results_list.Add(RunTest(DbType.Sqlite, false, false));
                results_list.Add(RunTest(DbType.Sqlite, false, true));
                results_list.Add(RunTest(DbType.Sqlite, true, false));
                results_list.Add(RunTest(DbType.Sqlite, true, true));
                results_list.Add(RunTest(DbType.Sqlce, false));
                results_list.Add(RunTest(DbType.Sqlce, true));                
            }
    
            foreach (var test_detail in results_list.GroupBy(r => r.test_details)) {
                Console.WriteLine(test_detail.Key);
                Console.WriteLine("Creating table: {0} ms", test_detail.Average(r => r.create_table_time));
                Console.WriteLine("Inserting data: {0} ms", test_detail.Average(r => r.insert_time));
                Console.WriteLine("Updating data: {0} ms", test_detail.Average(r => r.update_time));
                Console.WriteLine("Selecting data: {0} ms", test_detail.Average(r => r.select_time));
                Console.WriteLine("Deleting data: {0} ms", test_detail.Average(r => r.delete_time));
                Console.WriteLine("Dropping table: {0} ms", test_detail.Average(r => r.drop_table_time));
                Console.WriteLine();
            }
        }
    
        static Results RunTest(DbType db_type, bool use_trx, bool use_wal = false)
        {
            DbConnection conn = null;
            if (db_type == DbType.Sqlite)
                conn = GetConnectionSqlite(use_wal);
            else
                conn = GetConnectionSqlce();
    
            Results results = new Results();
            results.test_details = string.Format("Testing: {0}, transactions: {1}, WAL: {2}", db_type, use_trx, use_wal);
            results.create_table_time = CreateTable(conn, db_type);
            results.insert_time = InsertTime(conn, use_trx);
            results.update_time = UpdateTime(conn, use_trx);
            results.select_time = SelectTime(conn, use_trx);
            results.delete_time = DeleteTime(conn, use_trx);
            results.drop_table_time = DropTableTime(conn);
            conn.Close();
            return results;
        }
    
        static DbConnection GetConnectionSqlite(bool use_wal)
        {
            SQLiteConnection conn = new SQLiteConnection("Data Source=sqlite.db");
            if (!File.Exists(conn.Database))
                SQLiteConnection.CreateFile("sqlite.db");
            conn.Open();
            if (use_wal) {
                var command = conn.CreateCommand();
                command.CommandText = "PRAGMA journal_mode=WAL";
                command.ExecuteNonQuery();
            }
            return conn;
        }
    
        static DbConnection GetConnectionSqlce()
        {
            SqlCeConnection conn = new SqlCeConnection("Data Source=sqlce.sdf");
            if (!File.Exists(conn.Database))
                using (var sqlCeEngine = new SqlCeEngine("Data Source=sqlce.sdf"))
                    sqlCeEngine.CreateDatabase();
            conn.Open();
            return conn;
        }
    
        static long CreateTable(DbConnection con, DbType db_type)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var sqlcmd = con.CreateCommand();
            if (db_type == DbType.Sqlite)
                sqlcmd.CommandText = create_table_sqlite;
            else
                sqlcmd.CommandText = create_table_sqlce;
            sqlcmd.ExecuteNonQuery();
            return sw.ElapsedMilliseconds;
        }
    
        static long DropTableTime(DbConnection con)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var sqlcmd = con.CreateCommand();
            sqlcmd.CommandText = drop_table;
            sqlcmd.ExecuteNonQuery();
            return sw.ElapsedMilliseconds;
        }
    
        static long InsertTime(DbConnection con, bool use_trx)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var sqlcmd = con.CreateCommand();
            DbTransaction trx = null;
            if (use_trx) {
                trx = con.BeginTransaction();
                sqlcmd.Transaction = trx;
            }
            for (int i = 0; i < NUMBER_OF_TESTS; i++) {
                sqlcmd.CommandText = string.Format(insert_data, Guid.NewGuid().ToString());
                sqlcmd.ExecuteNonQuery();
            }
            if (trx != null)
                trx.Commit();
            return sw.ElapsedMilliseconds;
        }
    
        static long SelectTime(DbConnection con, bool use_trx)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var sqlcmd = con.CreateCommand();
            DbTransaction trx = null;
            if (use_trx) {
                trx = con.BeginTransaction();
                sqlcmd.Transaction = trx;
            }
            Random rnd = new Random(DateTime.Now.Millisecond);
            for (var max = NUMBER_OF_TESTS; max-- > 0; ) {
                sqlcmd.CommandText = string.Format(read_data, rnd.Next(1, NUMBER_OF_TESTS - 1));
                sqlcmd.ExecuteNonQuery();
            }
            if (trx != null)
                trx.Commit();
            return sw.ElapsedMilliseconds;
        }
    
        static long UpdateTime(DbConnection con, bool use_trx)
        {
            Stopwatch sw = Stopwatch.StartNew();
            var sqlcmd = con.CreateCommand();
            DbTransaction trx = null;
            if (use_trx) {
                trx = con.BeginTransaction();
                sqlcmd.Transaction = trx;
            }
            Random rnd = new Random(DateTime.Now.Millisecond);
            for (var max = NUMBER_OF_TESTS; max-- > 0; ) {
                sqlcmd.CommandText = string.Format(update_data, rnd.Next(1, NUMBER_OF_TESTS - 1), Guid.NewGuid().ToString());
                sqlcmd.ExecuteNonQuery();
            }
            if (trx != null)
                trx.Commit();
            return sw.ElapsedMilliseconds;
        }
    
        static long DeleteTime(DbConnection con, bool use_trx)
        {
            Stopwatch sw = Stopwatch.StartNew();
            Random rnd = new Random(DateTime.Now.Millisecond);
            var order = Enumerable.Range(1, NUMBER_OF_TESTS).ToArray();
            Action swap = (arr, a, b) => { int c = arr[a]; arr[a] = arr[b]; arr[b] = c; };
            var sqlcmd = con.CreateCommand();
            DbTransaction trx = null;
            if (use_trx) {
                trx = con.BeginTransaction();
                sqlcmd.Transaction = trx;
            }
            // shuffling the array
            for (var max = NUMBER_OF_TESTS; max-- > 0; ) swap(order, rnd.Next(0, NUMBER_OF_TESTS - 1), rnd.Next(0, NUMBER_OF_TESTS - 1));
    
            foreach (int index in order) {
                sqlcmd.CommandText = string.Format(delete_data, index);
                sqlcmd.ExecuteNonQuery();
            }
            if (trx != null)
                trx.Commit();
            return sw.ElapsedMilliseconds;
        }
    }
    

    Here are the numbers I get:

    Testing: Sqlite, transactions: False, WAL: False
    Creating table: 24.4 ms
    Inserting data: 3084.7 ms
    Updating data: 3147.8 ms
    Selecting data: 30 ms
    Deleting data: 3182.6 ms
    Dropping table: 14.5 ms
    
    Testing: Sqlite, transactions: False, WAL: True
    Creating table: 2.3 ms
    Inserting data: 14 ms
    Updating data: 12.2 ms
    Selecting data: 6.8 ms
    Deleting data: 11.7 ms
    Dropping table: 0 ms
    
    Testing: Sqlite, transactions: True, WAL: False
    Creating table: 13.5 ms
    Inserting data: 20.3 ms
    Updating data: 24.5 ms
    Selecting data: 7.8 ms
    Deleting data: 22.3 ms
    Dropping table: 16.7 ms
    
    Testing: Sqlite, transactions: True, WAL: True
    Creating table: 3.2 ms
    Inserting data: 5.8 ms
    Updating data: 4.9 ms
    Selecting data: 4.4 ms
    Deleting data: 3.8 ms
    Dropping table: 0 ms
    
    Testing: Sqlce, transactions: False, WAL: False
    Creating table: 2.8 ms
    Inserting data: 24.4 ms
    Updating data: 42.8 ms
    Selecting data: 30.4 ms
    Deleting data: 38.3 ms
    Dropping table: 3.3 ms
    
    Testing: Sqlce, transactions: True, WAL: False
    Creating table: 2.1 ms
    Inserting data: 24.6 ms
    Updating data: 44.2 ms
    Selecting data: 32 ms
    Deleting data: 37.8 ms
    Dropping table: 3.2 ms
    

    ~3 seconds for 200 inserts or updates using sqlite might still seem a little high, but at least it's more reasonable than 23 seconds. Conversely, one might be worried how SqlCe takes too little time to complete the same 200 inserts or update, especially since there seems to be no real speed difference between having each SQL query in individual transactions, or together in one transaction. I don't know enough about SqlCe to explain this, but it worries me. Would it mean that when .Commit() returns, you are not assured that the changes are actually written to disk?

提交回复
热议问题