QLite大量插入的效率问题

http://www.cnblogs.com/rader/articles/1543760.html

这两天再做一个数据转换的程序,讲原来用二进制形势存储的数据转换到SQLite数据库中去。记录总共有1千万多点。开发使用的是.net framework 3.5 sp1的环境,所以直接使用了EntityFramework方便数据库的操作。EntityFramework倒是省了一些事情,可是效率上让人无法忍受。整个程序运行一次花了40多分钟。利用EntityFramework,首先从数据库生成模型,然后我这样来保存数据:

1
2
3
4
5
6
7
8
using (GameSetEntities gse = new GameSetEntities(CreateConnection()))
{
    foreach (var ticket in tickets)
    {
        gse.AddToShuffledTicketSet(ticket);
    }
    gse.SaveChanges(true);
}

Ticket是我要插入数据库中的记录。一千多万条记录,我是分成5000条一批进行处理的。5000条记录先被添加到GameSetEntities(DataContext)中,然后进行提交。

利用StopWatch,我记录了这5000条记录插入数据库所消耗的时间,平均是1.1秒。(2080 * 1.1)/60 大约是36分钟,也就是说整个程序的运行时间中有80%多的时间是花在了数据库的插入操作上。插入5000条记录平均花费1.1秒,这个速度实在太慢了。我开始怀疑是不是EntityFramework效率问题?既然这样那就比比看吧,看看纯粹的ado.net代码是不是比它快。下面是纯手工的数据库操作代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using (DbConnection conn = DbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection())
            {
                conn.ConnectionString = "Data Source = " + m_datasourceFile + ";Version = 3";
                using (SQLiteCommand insertRngCmd = (SQLiteCommand)conn.CreateCommand())
                {
                    insertRngCmd.CommandText = @"INSERT INTO shuffled_tickets (ticket_idx, seed, win_credits, [timestamp], redeemed, prog_levels)
                                                    VALUES  (@ticket_idx, @seed, @win_credits, @timestamp, @redeemed, @prog_levels)";
                    conn.Open();
                    foreach (var ticket in tickets)
                    {
                        insertRngCmd.Parameters.AddWithValue("@ticket_idx", ticket.ticket_idx);
                        insertRngCmd.Parameters.AddWithValue("@seed", ticket.seed);
                        insertRngCmd.Parameters.AddWithValue("@win_credits", ticket.win_credits);
                        insertRngCmd.Parameters.AddWithValue("@timestamp", ticket.timestamp);
                        insertRngCmd.Parameters.AddWithValue("@redeemed", ticket.redeemed);
                        insertRngCmd.Parameters.AddWithValue("@prog_levels", ticket.prog_levels);
                        insertRngCmd.ExecuteNonQuery();
                    }
                }
            }

这样的代码一运行,发现速度更慢了,5000记录居然要20秒的时间……看来问题不是在这里。

Google一番之后,在Sqlite.net ADO Provider的论坛里发现这篇文章:Fastest Bulk Inserts.在最后一个例子“Fastest universal way to insert data using standard ADO.NET constructs”中作者提到“100,000 inserts on my machine in 1.4 seconds”--10万条记录插入耗时1.4秒。我才5000条不应该需要20秒那么慢的(用EntityFramework需要1.1秒,后来分析应该是内部使用了批量插入操作),看来是我的代码写的有问题。仔细阅读了作者给的例子之后发现,我们代码的差别主要在于事务的使用上。作者给的例子使用事务一次性提交10万条记录,而我的代码没有使用事务,而是每次提交。于是我改写了一下我的代码,也加上事务进行提交:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using (DbConnection conn = DbProviderFactories.GetFactory("System.Data.SQLite").CreateConnection())
{
    conn.ConnectionString = "Data Source = " + m_datasourceFile + ";Version = 3";
     
    using (SQLiteCommand insertRngCmd = (SQLiteCommand)conn.CreateCommand())
    {
        insertRngCmd.CommandText = @"INSERT INTO shuffled_tickets (ticket_idx, seed, win_credits, [timestamp], redeemed, prog_levels)
                                        VALUES  (@ticket_idx, @seed, @win_credits, @timestamp, @redeemed, @prog_levels)";
        conn.Open();
        var transaction = conn.BeginTransaction();  
        foreach (var ticket in tickets)
        {
            insertRngCmd.Parameters.AddWithValue("@ticket_idx", ticket.ticket_idx);
            insertRngCmd.Parameters.AddWithValue("@seed", ticket.seed);
            insertRngCmd.Parameters.AddWithValue("@win_credits", ticket.win_credits);
            insertRngCmd.Parameters.AddWithValue("@timestamp", ticket.timestamp);
            insertRngCmd.Parameters.AddWithValue("@redeemed", ticket.redeemed);
            insertRngCmd.Parameters.AddWithValue("@prog_levels", ticket.prog_levels);
            insertRngCmd.ExecuteNonQuery();
        }
        transaction.Commit();
    }

结果5000条记录的插入时间由原来的1.1秒变为0.09秒,这是一个非常大的提升。

但是为什么加上一个事务之后的差别这么大呢?我翻了翻Sqlite的文档,“Database Speed Comparison”里有解释:

在“Test1:1000 INSERTS”下面有一句话:……“In this test, each SQL statement is a separate transaction so the database file must be opened and closed and the cache must be flushed 1000 times”……

在“Test 2:25000 INSERT in a transaction”下面有另外一句话:……“When all the INSERTs are put in a transaction, SQLite no longer has to close and reopen the database or invalidate its cache between each statement. ”……

从上面两句话看来,没有事务的时候,SQLite的插入操作使用了太多的IO操作,而是用事务的话,只需要一次IO。

C#:SQLite大量插入的效率问题相关推荐

  1. SQLITE高速插入数据

    SQLITE数据库在写入数据时,写入数据库的速度非常重要,如果写入的速度慢,有大量数据待写入时,一是会造成程序卡顿,二是数据写入会失败,数据缺失. 传统的往数据库里插入数据是执行一条SQL语句,多条数 ...

  2. android SQLite 批量插入数据慢的解决方案 (针对于不同的android api 版本)

    android SQLite 批量插入数据慢的解决方案 (针对于不同的android api 版本) 参考文章: (1)android SQLite 批量插入数据慢的解决方案 (针对于不同的andro ...

  3. SQLite解决插入大量数据速度慢的问题

    SQLite解决插入大量数据速度慢的问题 背景 在重构公司项目中发现,公司以前代码中将大量数据插入SQLite数据库,速度非常慢,几千条居然需要将近1分钟: 解决方法 知识背景 事务(Transact ...

  4. SQLite批量插入效率

    一.循环单条数据插入 SQLite插入单条数据效率并不高,原因是: Because it does not have a central server to coordinate access, SQ ...

  5. anroid Sqlite批量插入数据优化方法

    SQLite的数据库本质上来讲就是一个磁盘上的文件,所以一切的数据库操作其实都会转化为对文件的操作,而频繁的文件操作将会是一个很好时的过程,会极大地影响数据库存取的速度. 例如:向数据库中插入100万 ...

  6. sqlite c++插入 timestamp_Dqlite,基于sqlite 高可用(HA)数据库

    原文发表于我的博客, 特此版权声明 noosphere.site: Dqlite,基于sqlite 高可用(HA)数据库 csdn : Dqlite,基于sqlite 高可用(HA)数据库 k3s之前 ...

  7. 颠覆:链表在删除和插入的效率一定优于数组吗?

    在大二我们学校的计算机大赛中,出了一道题目:要求证明对于数组和链表进行500次随机访问,比较他们的运行时间.这道题目对于我们程序员来说,可能潜在的答案是链表肯定是快的,但是结果呢? 其实数组在计算机中 ...

  8. SQLite大批量插入性能优化

    SQLite作为轻量级,零安装的数据库,用在小型桌面应用程序上特别合适. 网上搜了一下,貌似在程序中无法直接从格式化文本或CSV文件导入SQLite,只能逐条insert,这一点比起SQL SERVE ...

  9. android sqlite批量操作,Android: SQLite批量插入数据的最佳实践

    大家都知道,Android里数据库用的是SQLite.在实际开发过程中,我们有时候会遇到批量插入数据的场景.这篇文章给大家分享一个小技巧,让批量插入数据达到最快的目的. 首先,我先创建一个Table, ...

  10. 安卓mysql插入数据_【11-25求助】关于Android 的SQLite数据库插入数据报错问题

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 运行程序,不知道为何点插入数据按钮会报错,请万能的吧友帮我看看,谢谢,不废话,直接上代码 MainActivity.java package com.ex ...

最新文章

  1. c语言编写pdf,编写并运行C语言程序.pdf
  2. 我向面试官讲解了单例模式,他对我竖起了大拇指
  3. upstream directive is not allowed here in
  4. docker rabbitmq_RabbitMQ消息中间件快速入门
  5. CSDN重推软件下载频道 软件发布又有新阵地
  6. 【转】Latex入门教程
  7. c语言mud游戏制作,MUD游戏制作工具下载
  8. CountDownLatch 用法和源码解析
  9. 日本知名动画公司东映动画加入 The Sandbox 元宇宙
  10. Java实现23种设计模式教程(作者原创)
  11. 16 最小二乘法 - 数据分析的瑞士军刀
  12. 米饭里加点它,4大病症全没了!一定要告诉家里做饭的TA
  13. Quartus II的破解之道
  14. PaddlePaddle 系列之三行代码从入门到精通
  15. ESP32 开发笔记(八)ESP32 MP3 播放器
  16. 计算机科学在本质上源自,计算机与信息技术基础(第4版)第1章.ppt
  17. HighTec编译器提高编译速度
  18. dhcp地址分配信息是什么_DHCP动态网段分配|必看
  19. 时间序列深度学习:状态 LSTM 模型预測太阳黑子(一)
  20. 6S大气传输模型修改源码添加、自定义CASI传感器光谱响应

热门文章

  1. VMware下Ubuntu与宿主Windows共享文件夹
  2. 【技术贴】解决开机本地连接出来慢,本地连接开机后出来时间慢
  3. 谢谢你,阅读了这篇文章
  4. 宏基ACER Aspire R3600 REVO离子平台
  5. ECharts-第一篇最简单的应用
  6. maven搭建mybatis测试
  7. Python的JAVA胶水——jpype
  8. Unity3D倒计时两种方法
  9. 使用git第一次成功,记录
  10. 老程序员应该记住的 5 件事