【问题标题】:SQL Server CE 4.0 performance comparisonSQL Server CE 4.0 性能比较
【发布时间】:2011-07-12 01:52:12
【问题描述】:

SQL Server CE 4(SQL Server Compact Edition 4.0)已经不是新闻了(如果是,你可以read this article)

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

尤其是:

  • SQLite
  • SQL Server (1)
  • SQL Server Express *
  • 也许是火鸟

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

不幸的是,谷歌目前提供的关于该主题的链接并不多。实际上我找不到任何东西(对于正确的 SQL CE 版本)。

如果有人可以找到或分享此类信息,请在此处收集它以供未来人类使用。

【问题讨论】:

  • Desktop Benchmark Roundup 还有另一个旧基准。它使用 C# 提供程序来访问 SQLite,所以如果您直接使用 C,我想它会快一点。如果您运行自己的基准测试,请发布结果。
  • 通常,性能与您的设计和代码有关。平台的选择并不重要。可支持性、功能集、企业标准、多用户或无关紧要。 SQL CE 只能在这个分数上与 SQLite 进行比较。如果您想要多用户,您将使用常见且可扩展的 SQL Server Express。第二个@Ash Machine:问题是什么?
  • 与 sqlite 相比,SqlCe 总是给我更好的插入速度。

标签: sql-server performance sqlite sql-server-ce


【解决方案1】:

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

它们的主要区别在于通用服务器端关系数据库(如MS SQL、MySQL、Firebird Classic和SuperServer等)作为独立服务安装,在您的主应用程序范围之外运行。这就是为什么它们可以更好地执行,因为对多核和多 CPU 架构的内在支持,使用预缓存、VSS 等操作系统功能来增加密集型数据库操作的吞吐量,并且可以要求尽可能多的内存您的操作系统可以提供单个服务/应用程序。这也意味着它们的性能指标或多或少独立于您的应用程序,但很大程度上取决于您的硬件。在这方面,我想说任何数据库的服务器版本总是比嵌入式版本的性能更好。

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

由于应用程序的不同领域,这些数据库具有不同的选项板:server-db 提供广泛的用户和权限管理、对视图和存储过程的支持,而嵌入式数据库通常缺乏对用户和权限管理的任何支持,并且功能有限支持视图和存储过程(后者失去了在服务器端运行的大部分好处)。数据吞吐量是 RDBMS 的常见瓶颈,服务器版本通常安装在条带化 RAID 卷上,而嵌入式 DB 通常面向内存(尽量将所有实际数据保留在内存中)并最大限度地减少数据存储访问操作。

因此,比较适用于 .Net 的不同嵌入式 RDBMS 的性能可能是有意义的,例如 MS SQL CE 4.0、SQLite、Firebird Embedded、TurboSQL。 我不希望在通常的非高峰操作期间出现巨大差异,但由于与操作系统更好的集成,某些数据库可能会为大型 BLOB 提供更好的支持。

-- 更新--

我不得不收回我的遗言,因为我的快速实施显​​示了非常有趣的结果。

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

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 Enterprise。
  2. 我使用两个数据库的默认设置和连接字符串“Data Source=database_file_name”。
  3. 我使用了最新版本的 SQL CE 4.0 和 SQLite/System.Data.SQLite(从今天开始,2011 年 6 月 3 日)。

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

> =测试嵌入式数据库的 CRUD 性能= > => 样本大小:200 > ==测试 SQLite== > 创建表:396.0396 毫秒 > 写入数据:22189.2187 ms > 更新数据:23591.3589 毫秒 > 读取数据:21.0021 毫秒 > 删除数据:20963.0961 ms > 丢弃表:85.0085 毫秒 > ==测试 SQL CE 4.0== > 创建表:16.0016 毫秒 > 写入数据:25.0025 毫秒 > 更新数据:56.0056 毫秒 > 读取数据:28.0028 ms > 删除数据:53.0053 毫秒 > 丢弃表:11.0011 毫秒

...以及更大的样本:

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

因此,如您所见,与 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 适配器):从数据连接意外关闭到数据库文件损坏。我认为数据适配器或库本身存在一些稳定性问题。

【讨论】:

  • 糟糕,我只是在编辑我的帖子时误点击并进入了社区 wiki 条目。可惜:(
  • 有趣的是,SQLite 通常用作内存中存储的数据库,并且很少刷新它。你会在你的测试中尝试这种使用 SQLite 的模式吗?
  • 是的,下个版本我会考虑几种模式。在此处查看我的第二个答案以及我在 CodeProject 网站上发布的文章。并感谢您的赏金!
  • 将您的 sqlite 更新代码放入事务中,它将击败 sqlce 代码。这是一个众所周知的设计决策,不这样做是不诚实的。
  • 更新:我刚刚尝试过这个源代码,我发现当实际以ExecuteReader 运行读取查询时,您会发现 SQLite 比 SQL CE 更严重的性能损失(我假设您实际上想要查询结果)。这是因为reader[int] 是使用 P/Invoke 实现的。
【解决方案2】:

这是我在 CodeProject 网页上关于基准测试的新鲜出炉的文章:

Benchmarking the performance of embedded DB for .Net: SQL CE 4.0 vs SQLite

(文章现在处于待处理状态,您需要登录CodeProject才能访问其内容)

P.S.:我错误地将我之前的答案标记为社区 wiki 条目,因此不会获得任何声誉。这鼓励了我为Code Project 撰写有关此主题的文章,其中包含一些优化的代码、有关嵌入式数据库的更多附加信息和结果的统计分析。所以,如果你喜欢这篇文章和我在这里的第二个答案,请投票给这个答案。

【讨论】:

  • 非常感谢您为实际提出这些测试所做的努力。这里的问题是您提供的数字根本没有意义;然后你让它让你得出一个可怕的结论,即应该如何通过 sqlite 来查看 ms sql ce;这是适得其反和烦人的。在发布此类不应有的结论之前,请尝试修复您的测试。
  • 我刚刚看了你的测试。我对此有一个主要抱怨。您正在将 READ 作为 ExecuteNonQuery 运行。但是,根据我有限的经验,SQLite 读取性能的最大开销是每个reader[int] 调用 P/Invokes 到 SQLite 本机。这意味着大型查询将非常缓慢。
  • 谢谢!正是我想要的
  • 支持此答案以感谢您在上一个答案中所做的努力,像您这样的人使地球旋转 ;)
【解决方案3】:

因为我对 Alaudo 的测试、测试结果以及最终得出的结论感到非常困难,所以我继续尝试了一下他的程序并想出了一个修改版本。

分别测试以下 10 次并输出平均次数:

  • 没有事务的sqlite,使用默认的jounal_mode
  • 带有事务的sqlite,使用默认的journal_mode
  • 没有事务的sqlite,使用WAL jounal_mode
  • 带有事务的sqlite,使用WAL journal_mode
  • 没有事务的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 达到了非常好的性能。
【解决方案4】:

我最近参与了一个使用 SQL CE 4 和 NHibernate 的项目,我发现性能非常好。使用 SQL CE 4,我们能够在一秒钟内插入 8000 条记录。借助网络上的 Oracle,即使使用了批量大小和 seqhilo 方法,我们也只能每秒插入 100 条记录。

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

只是避免使用标识列,我们注意到如果不使用它们,性能会提高 40 倍。当 Identity 列用作 PK 时,插入相同的 8000 条记录需要 40 秒。

【讨论】:

  • 真的,身份列有那么糟糕吗?这可能解释了我看到的一些性能问题。
  • 很棒的提示!我正在使用 SQL CE 4 和 Fluent NHibernate 开展一个项目,通过从身份切换到 hilo 主键,我们的插入速度提高了 30 倍。
  • 不确定这是否与此处提到的身份问题有关,但在使用服务器生成的 ID 和 SQL Server Compact 4.0 时,Entity Framework 5 存在错误。见:stackoverflow.com/questions/14768394/…
  • 我不知道 SQL CE 和 EF 中的那个问题,无论如何,只要在 NHibernate 的往返行程中可行,我就将上述方法与 SQL Server 和 Oracle 一起使用以获得新的recordId 是性能杀手。在提交所有更改之前,EF 不会提供 ID,这在某些情况下(在层级应用程序中创建 Dto)至少可以说是一件痛苦的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 2012-03-01
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 2017-07-11
相关资源
最近更新 更多