加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 18:18:47 所属栏目:百科 来源:网络整理
导读:历史 我有一个“记录”列表(3,500),我保存到XML并在程序退出时压缩.以来: 记录数量增加 退出时只需要更新大约50条记录 节省大约需要3秒钟 我需要另一个解决方案 – 嵌入式数据我之所以选择SQL CE,是因为它与VS一起使用没有任何问题,许可证对我来说是好的(我
历史

我有一个“记录”列表(3,500),我保存到XML并在程序退出时压缩.以来:

>记录数量增加
>退出时只需要更新大约50条记录
>节省大约需要3秒钟

我需要另一个解决方案 – 嵌入式数据我之所以选择SQL CE,是因为它与VS一起使用没有任何问题,许可证对我来说是好的(我将它与Firebird,SQLite,EffiProz,db4o和BerkeleyDB进行了比较).

数据

记录结构:11个字段,其中2个构成主键(nvarchar字节).其他记录是字节,数据时间,双精度和整数.

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

LINQ方法

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

执行时间处理时间? 4分52秒我昏了过去(记住你:XML压缩= 3秒).

SQL CE原始方法

我用谷歌搜索了一下,尽管有这样的说法:
LINQ to SQL (CE) speed versus SqlCe
说它是SQL CE本身的错,我试了一下.

相同的循环,但这次插入是使用SqlCeResultSet(DirectTable模式,请参阅:Bulk Insert In SQL Server CE)和SqlCeUpdatableRecord.

结果?你坐得舒服吗?好吧…… 0.3秒(是的,第二个的一小部分!).

问题

LINQ非常易读,原始操作完全相反.我可以编写一个映射器,将所有列索引转换为有意义的名称,但它似乎重新发明轮子 – 毕竟它已经在… 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.ExecuteResultSet(ResultSetOptions.Updatable);

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

    record = rs.CreateRecord();

    int col = 0;
    record.SetString(col++,entry.Text);
    record.SetByte(col++,(byte)entry.dir);
    record.SetByte(col++,(byte)entry.LastLearningInfo.status.Value);
    // ... and so on

    rs.Insert(record);
}

解决方法

每笔交易做更多工作.

对于典型的关系数据库,提交通常是非常昂贵的操作,因为数据库必须等待磁盘刷新以确保数据不会丢失(ACID guarantees和所有这些).没有专业控制器的传统HDD磁盘IO在这种操作中非常慢:数据必须刷新到物理磁盘 – 也许只有30-60次提交可以在一秒钟之间发生IO同步!

请参阅SQLite FAQ:INSERT is really slow – I can only do few dozen INSERTs per second.忽略不同的数据库引擎,这是完全相同的问题.

通常,LINQ2SQL在SubmitChanges中创建一个新的隐式事务.要避免这种隐式事务/提交(提交是昂贵的操作):

>少调用SubmitChanges(比如,一次在循环外)或;
>设置显式事务范围(参见TransactionScope).

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

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更新,更改乐观并发模型(禁用它或仅使用时间戳字段)可能会导致小的性能改进.然而,最大的改进将来自减少必须执行的提交数量.

快乐的编码.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读