SQL Server CE 4.0 性能比较

37

SQL Server CE 4 (SQL Server Compact Edition 4.0)已经不是新闻了(如果是,您可以阅读此文章)。

但是看到SQL Server CE 4与其他数据库的性能比较仍然非常有趣。

特别是与以下数据库进行比较:

  • SQLite
  • SQL Server(1)
  • SQL Server Express *
  • 可能还包括Firebird

(1)对于功能相当的应用程序。

不幸的是,谷歌目前提供的有关这个主题的链接并不多。事实上,我未能找到任何(适用于正确的SQL CE版本)。

如果能够找到或分享这样的信息,让我们在这里收集它以供将来使用。


还有另一个旧的基准测试在桌面基准测试汇总。它使用C#提供程序来访问SQLite,所以如果您直接使用C,我想它会快一点。如果您运行自己的基准测试,请发布结果。 - Giorgi
通常,性能与您的设计和代码有关。平台的选择并不太重要。支持性、功能集、企业标准、是否多用户更为重要。在这方面,应将SQL CE与SQLite进行比较。如果您需要多用户,则应使用常见且可扩展的SQL Server Express。第二个@Ash机器:问题是什么? - gbn
SqlCe相比sqlite在插入速度方面一直表现得更好。 - nawfal
4个回答

16

在我看来,将嵌入式数据库(如SQL CE)与服务器端关系型数据库(如除SQLite和Firebird Embedded版本之外的所有其他数据库)进行比较是不正确的。

它们之间的主要区别是,通用的服务器端关系型数据库(如MS SQL,MySQL,Firebird Classic和SuperServer等)作为独立服务安装,并在您的主应用程序范围之外运行。这就是为什么它们可以性能更好的原因,因为它们天生支持多核和多CPU架构,使用操作系统功能(如预缓存,VSS等)来增加强大的数据库操作吞吐量,并且可以申请与您的操作系统提供给单个服务/应用程序一样多的内存。这也意味着它们的性能指标与您的应用程序或多或少独立,但在很大程度上取决于您的硬件。从这个角度来看,我会说任何数据库的服务器版本始终比嵌入式版本更具性能。

SQL CE(以及Firebird Embedded、SQLite、TurboSQL和一些其他嵌入式DB引擎)是嵌入式DB引擎,这意味着整个数据库打包到单个(或最多2个)DLL文件中,这些DLL文件与您的应用程序一起分发。由于明显的大小限制(您是否想一起分发30 MB的DLL和2-3 MB长的应用程序?),它们也直接在您的应用程序上下文中运行,并且数据访问操作的总内存和性能与应用程序的其他部分共享--这涉及可用内存,CPU时间,磁盘吞吐量等。并行运行计算密集型线程和数据访问线程可能导致数据库性能显著降低。

由于这些数据库的不同应用领域,它们具有不同的选项调色板:服务器DB提供广泛的用户和权限管理,支持视图和存储过程,而嵌入式数据库通常缺乏任何用户和权限管理的支持,并且对视图和存储过程的支持有限(后者在服务器端运行时失去了其大部分优势)。数据吞吐量是关系型数据库的一个瓶颈,服务器版本通常安装在条带化RAID卷上,而嵌入式DB通常是面向内存的(尝试将所有实际数据保留在内存中)并且最小化数据存储访问操作。

因此,“可能有意义的是比较不同的嵌入式.NET RDBMS的性能,例如MS SQL CE 4.0,SQLite,Firebird Embedded,TurboSQL”。

-- 更新 --

我要收回我的最后一句话,因为我快速实现显示出非常有趣的结果。

我编写了一个简短的控制台应用程序来测试两个数据提供程序,如果您想自己尝试它们,请看这里的源代码。

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


    }
}

必要的免责声明:

  1. 我在我的机器上获得了这些结果:Dell Precision WorkStation T7400配备有2个Intel Xeon E5420 CPU和8GB RAM,运行64位Win7企业版
  2. 我使用“Data Source = database_file_name”连接字符串为两个默认设置的DB。
  3. 我使用了最新版本的SQL CE 4.0和SQLite/System.Data.SQLite(从今天,2011年6月3日)。

以下是两个不同样本的结果:

> =测试嵌入式数据库的CRUD性能=  
> => 样本大小:200
> ==测试SQLite==
> 创建表:396.0396毫秒
> 写入数据:22189.2187毫秒
> 更新数据:23591.3589毫秒
> 读取数据:21.0021毫秒
> 删除数据:20963.0961毫秒
> 删除表:85.0085毫秒

> ==测试SQL CE 4.0==
> 创建表:16.0016毫秒
> 写入数据:25.0025毫秒
> 更新数据:56.0056毫秒
> 读取数据:28.0028毫秒
> 删除数据:53.0053毫秒
> 删除表:11.0011毫秒

...还有一个更大的样本:

=测试嵌入式数据库的CRUD性能=
 => 样本大小:1000
==测试SQLite==
创建表:93.0093毫秒
写入数据:116632.6621毫秒
更新数据:104967.4957毫秒
读取数据:134.0134毫秒
删除数据:107666.7656毫秒
删除表:83.0083毫秒
==测试SQL CE 4.0== 创建表:16.0016毫秒 写入数据:128.0128毫秒 更新数据:307.0307毫秒 读取数据:164.0164毫秒 删除数据:306.0306毫秒 删除表:13.0013毫秒

因此,正如您所看到的,与SQLCE相比,任何编写操作(创建、更新、删除)在SQLite中需要几乎1000倍的时间。这并不一定反映了这个数据库的普遍低性能,可能是由于以下原因:

  1. 我使用的SQLite数据提供程序是System.Data.SQLite,它是一个混合程序集,包含托管和非托管代码(SQLite最初完全由C编写,DLL仅提供绑定)。可能的P / Invoke和数据转换会消耗大量操作时间。
  2. SQLCE 4.0很可能默认将所有数据缓存在内存中,而每次发生更改时,SQLite会将大部分数据更改直接刷新到磁盘存储器中。可以通过连接字符串为两个数据库提供数百个参数,并适当调整它们。
  3. 我使用了一系列单个查询来测试数据库。至少SQLCE支持通过特殊的.NET类进行批量操作,这对此处更加合适。如果SQLite也支持它们(很抱歉,我不是专家,在快速搜索中没有找到有希望的结果),也很好比较它们。
  4. 在x64机器上使用SQLite时(使用相同的.NET适配器),我观察到许多问题:从数据连接意外关闭到数据库文件损坏。我认为数据适配器或库本身存在某些稳定性问题。

哎呀,我在编辑帖子时不小心点错了,把它变成了社区维基条目。可惜 :( - Alexander Galkin
有趣的是,SQLite通常被用作内存中存储的数据库,并且相对较少地进行刷新。在您的测试中,您是否会尝试使用这种SQLite的方式? - MajesticRa
是的,我会在下一个版本中考虑几种模式。请参阅我在此处的第二个答案以及我在CodeProject网站上发布的文章。 并且感谢您的悬赏! - Alexander Galkin
我看到你没有在Sqlite中使用事务,所以它才会这么慢。 - Giorgi
2
将您的SQLite更新代码放入事务中,它将轻松击败SQLCE代码。这是一个已知的设计决策,不这样做就是不诚实的行为。 - trampster
1
更新:我刚刚尝试了这段源代码,发现当实际运行读取查询作为“ExecuteReader”时,你会发现SQLite比SQL CE更耗费性能(我假设你实际上想要查询结果)。这是因为“reader[int]”是使用P/Invoke实现的。 - Aron

14

这是我新建的有关CodeProject网页基准测试的文章:

.Net嵌入式数据库性能基准测试: SQL CE 4.0 vs SQLite

(该文章现在处于待审核状态,你需要在CodeProject上登录才能访问其内容)

P.S .:我错误地将我的先前答案标记为社区维基条目,并且不会因此获得任何声望。这激励我为 Code Project 撰写关于此主题的文章,其中包括优化代码、更多关于嵌入式数据库的信息和结果的统计分析。因此,如果您喜欢这篇文章和我在这里的第二个答案,请投票支持我。


非常感谢你付出实际努力来设计这些测试。问题在于,你提供的数字根本毫无意义;然后你让它引导你得出一个可怕的结论,即应该优先考虑使用 MS SQL CE 而不是 SQLite;这是适得其反且令人烦恼的。请在发布此类不当结论之前尝试修复你的测试。 - user610650
我刚刚查看了你的测试。我对此有一个主要的抱怨。你正在将 READ 操作作为 ExecuteNonQuery 运行。但是,根据我的有限经验,SQLite 读取性能中最大的开销是每个 reader[int] 调用 P/Invokes 到 SQLite native。这意味着大查询将会非常慢。 - Aron
正是我所需要的 - user3382570
我点赞了这个回答,以表达我对你之前所做努力的感激之情。像你这样的人让地球转动着 ;) - Aniket Bhansali

10

因为我在Alaudo的测试、测试结果和最终结论方面遇到了很大的困难,所以我开始尝试修改他的程序,并得出了一个修改版。

它会对以下每个项目进行10次测试并输出平均时间:

  • 使用默认jounal_mode的sqlite无事务
  • 使用默认journal_mode的sqlite有事务
  • 使用WAL jounal_mode的sqlite无事务
  • 使用WAL journal_mode的sqlite有事务
  • 无事务的sqlce
  • 有事务的sqlce

这是程序(实际上是一个类):

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> results_list = new List<Results>();

        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<int>();
        Action<int[], int, int> 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;
    }
}

这是我得到的数字:

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

使用sqlite进行200次插入或更新可能仍需要大约3秒的时间,但至少比23秒更合理。相反,人们可能会担心SqlCe完成相同的200次插入或更新所需的时间太短,尤其是在单个事务中包含每个SQL查询与将它们分别放在各自的事务中之间似乎没有真正的速度差异时。我不了解关于SqlCe的足够信息来解释这一点,但这使我感到担忧。这是否意味着当.Commit()返回时,您不能确保更改实际上已写入磁盘?


很抱歉你在我的测试结果上遇到了困难。我之前没有写信是因为我正在这里对两个引擎进行详尽的测试,试图获得更多的真实统计数据。 除了你关于 .Commit() 的问题 - 我认为数据仍然被缓存,完成的事务只意味着数据被原子性地修改,而不是数据必须在 .Commit() 结束时被修改 - 我还注意到如果你将样本大小(每个测试中的行数)进一步增加到1000-2000-5000行,你会得到更好的差异。SQLite在那时达到了非常好的性能。 - Alexander Galkin

5

我最近参与了一个使用SQL CE 4和NHibernate的项目,发现性能非常好。使用SQL CE 4我们能够在一秒钟内插入8000条记录。在使用Oracle通过网络进行操作时,即使采用批量大小(batch-size)和seqhilo方法,每秒也只能够插入100条记录。

我没有进行测试,但是查看了一些针对.NET的NoSQL产品性能报告,SQL CE 4似乎是独立应用程序最好的解决方案之一。

只需避免使用Identity列,我们发现如果不使用Identity列,性能会提高40倍。当Identity列作为主键时,相同的8000条记录需要40秒才能够插入。


真的吗,标识列那么糟糕吗??这可能解释了我看到的一些性能问题。 - Brady Moritz
1
太棒了!我正在使用SQL CE 4和Fluent NHibernate开发一个项目,在将主键从identity切换到hilo后,插入速度提高了30倍。 - Joel V. Earnest-DeYoung
不确定这是否与此处提到的身份问题相关,但在使用服务器生成的ID和SQL Server Compact 4.0时,存在一个Entity Framework 5的错误。请参见:https://dev59.com/nG7Xa4cB1Zd3GeqPnTm5 - Dabblernl
我之前不知道SQL CE和EF中的那个问题,但无论如何,每当在NHibernate的往返中获取新的recordId是一个性能杀手时,我都会在可能的情况下使用上述方法来处理SQL Server和Oracle。EF直到所有更改都被提交后才提供ID,这对于某些情况(在层应用程序中创建Dto)可能是一种痛苦。 - ealbert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接