Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用SQL CE加速LINQ插入?_C#_.net_Linq_Optimization_Sql Server Ce - Fatal编程技术网

C# 如何使用SQL CE加速LINQ插入?

C# 如何使用SQL CE加速LINQ插入?,c#,.net,linq,optimization,sql-server-ce,C#,.net,Linq,Optimization,Sql Server Ce,历史 我有一个“记录”(3500)列表,我将其保存为XML,并在程序退出时进行压缩。自: 记录的数量增加了 只有大约50条记录需要在退出时更新 节省大约需要3秒钟 我需要另一个解决方案——嵌入式数据库。我选择SQL CE是因为它可以与VS一起工作,没有任何问题,而且许可证对我来说还可以(我将它与Firebird、SQLite、EffiProz、db4o和BerkeleyDB进行了比较) 数据 记录结构:11个字段,其中2个为主键(nvarchar+字节)。其他记录包括字节、数据时间、双精度和

历史

我有一个“记录”(3500)列表,我将其保存为XML,并在程序退出时进行压缩。自:

  • 记录的数量增加了
  • 只有大约50条记录需要在退出时更新
  • 节省大约需要3秒钟
我需要另一个解决方案——嵌入式数据库。我选择SQL CE是因为它可以与VS一起工作,没有任何问题,而且许可证对我来说还可以(我将它与FirebirdSQLiteEffiProzdb4oBerkeleyDB进行了比较)

数据

记录结构:11个字段,其中2个为主键(nvarchar+字节)。其他记录包括字节、数据时间、双精度和整数

我不使用任何关系、连接、索引(主键除外)、触发器、视图等。它实际上是一个平面字典——成对的键+值。我修改了其中一些,然后我必须在数据库中更新它们。我不时地添加一些新的“记录”,我需要存储(插入)它们。就这些

LINQ方法

我有一个空白的数据库(文件),所以我在一个循环中插入3500个(一个接一个)。我甚至不检查记录是否已经存在,因为db是空的

执行时间?4分52秒。我晕倒了(注意:XML+compress=3秒)

SQL CE原始方法

我在谷歌上搜索了一下,尽管有这样的说法: 说这是SQL CE本身的错,我试了一下

相同的循环,但这次是使用SqlCeResultSet(DirectTable模式,请参阅:)和SQLCEUpdateableRecord进行插入

结果如何?你坐得舒服吗?好。。。0.3秒(是的,秒的分数!)

问题

LINQ的可读性非常强,而原始操作则相反。我可以编写一个映射程序,将所有列索引转换为有意义的名称,但这似乎是在重新发明轮子——毕竟它已经在。。。林克

所以,也许这是告诉LINQ加快速度的一种方式问题——怎么做

代码

LINQ

foreach (var entry in dict.Entries.Where(it => it.AlteredByLearning))
{
    PrimLibrary.Database.Progress record = null;

        record = new PrimLibrary.Database.Progress();
        record.Text = entry.Text;
        record.Direction = (byte)entry.dir;
        db.Progress.InsertOnSubmit(record);

    record.Status = (byte)entry.LastLearningInfo.status.Value;
    // ... and so on

    db.SubmitChanges();
}
原始操作

SqlCeCommand cmd=conn.CreateCommand()

cmd.CommandText=“进度”; cmd.CommandType=System.Data.CommandType.TableDirect; SqlCeResultSet rs=cmd.executesultset(ResultSetOptions.updateable)


我对此不是很肯定,但似乎应该在循环之外进行
db.SubmitChanges()
调用。也许这会加快速度?

在每笔交易中做更多的工作。

对于典型的关系数据库,提交通常是非常昂贵的操作,因为数据库必须等待磁盘刷新以确保数据不会丢失(以及所有这些)。在这种操作中,没有专用控制器的传统HDD磁盘IO速度非常慢:数据必须刷新到物理磁盘上——在IO同步的情况下,一秒钟可能只有30-60次提交

请参阅SQLite常见问题解答:。忽略不同的数据库引擎,这是完全相同的问题

通常,LINQ2SQL在
SubmitChanges
内部创建一个新的隐式事务。要避免此隐式事务/提交(提交是昂贵的操作),请执行以下操作之一:

  • 调用
    SubmitChanges
    less(比如,一旦超出循环)或

  • 设置显式事务作用域(请参阅)

  • 使用更大事务上下文的一个示例是:

    using (var ts = new TransactionScope()) {
      // LINQ2SQL will automatically enlist in the transaction scope.
      // SubmitChanges now will NOT create a new transaction/commit each time.
      DoImportStuffThatRunsWithinASingleTransaction();
      // Important: Make sure to COMMIT the transaction.
      // (The transaction used for SubmitChanges is committed to the DB.)
      // This is when the disk sync actually has to happen,
      // but it only happens once, not 3500 times!
      ts.Complete();
    }
    
    但是,使用单个事务或单个SubmitChanges调用的方法的语义不同于上面调用SubmitChanges 3500次并创建3500个不同隐式事务的代码的语义。特别是,原子操作的大小(相对于数据库)不同,可能不适合所有任务

    对于LINQ2SQL更新,更改乐观并发模型(例如,禁用乐观并发模型或仅使用时间戳字段)可能会导致性能的微小改进。然而,最大的改进将来自减少必须执行的提交数量


    愉快的编码。

    你能展示一些代码示例吗?@Kevin Pullin,当然,我添加了必要的部分来了解如何在这两种情况下进行插入。你尝试过了吗?@svick,你能解释一下序列化对象与LINQ在这种情况下有什么关系吗?@macias,没什么,但你说保存到XML太慢了。使用
    BinaryFormatter
    比使用普通的SQL数据库更容易,速度也足够快。似乎您不了解实际数据库的大多数功能,所以更轻的可能更好(甚至更快)。尽管它就在我眼前,我故意忽略了这一点,认为在桌面环境中,这是可以忽略的,因为有两个因素——SQL CE引擎不会每次重新加载,也不会造成连接损失。哦,天哪,我离真相太远了——一次振作起来,我得到的不是5分钟,而是5秒(这比DirectTable慢了一个数量级,但对我来说还行)。谢谢你的冷水浴:-)。
    using (var ts = new TransactionScope()) {
      // LINQ2SQL will automatically enlist in the transaction scope.
      // SubmitChanges now will NOT create a new transaction/commit each time.
      DoImportStuffThatRunsWithinASingleTransaction();
      // Important: Make sure to COMMIT the transaction.
      // (The transaction used for SubmitChanges is committed to the DB.)
      // This is when the disk sync actually has to happen,
      // but it only happens once, not 3500 times!
      ts.Complete();
    }