zoukankan      html  css  js  c++  java
  • Sqlite大数据写入性能优化

      众所周知,Sqlite是一个轻量级的数据库,仅仅需要一个exe文件就能运行起来。在处理本地数据上,我比较喜欢选择使用它,不仅是因为他与sql server有着比较相近的语法,还因为它不需要安装,仅需要通过命令行就能启动了,而且他在处理大数据时,性能比sql server好很多,好吧这里不继续争论性能优劣。

      首先,这次的问题是在一次项目中遇到的,项目要求能大量导入数据,而且由于项目性质(轻便,本地化),所以我选择sqlite来存放数据。

      第一版代码:

    1 StringBuilder sql = new StringBuilder();
    2 foreach (DataRow dr in dt.Rows)
    3 {
    4     sql.Append("INSERT INTO Info (Name,Code) VALUES('"+dr[0]+"','"+dr[1]+"') 
    ");    
    5 }
    6 sqlHelper.SqliteHelper.ExecuteNonQuery( sql.ToString(), CommandType.Text);
    View Code

      从上面的代码看来,我没有进行任何优化工作,我用这种方式插入了1万条数据用了1分多钟,可见优化的重要性(百万级数据跑起来...不敢想象)。

      开启事务:

    1 StringBuilder sql = new StringBuilder();
    2 sql.Append("BEGIN;");//开启事务
    3 foreach (DataRow dr in dt.Rows)
    4 {
    5      sql.Append("INSERT INTO Info (Name,Code) VALUES('"+dr[0]+"','"+dr[1]+"') 
    ");    
    6 }
    7 sql.Append("COMMIT;");//提交事务
    8 sqlHelper.SqliteHelper.ExecuteNonQuery( sql.ToString(), CommandType.Text);
    View Code

          由于sqlite的数据操作实质上是对于其数据文件的IO操作,频繁的插入数据会导致文件IO经常开闭,非常损耗性能能。事务作用便是使数据先缓存在系统中,提交事务时便提交所有的更改到数据文件,此时数据文件的IO只需要开闭一次,且避免了长期占用文件IO所导致性能低下的问题。此时,开启事务处理后性能上虽然有了大幅度的提升,但是结果仍旧不理想,哪还有什么在影响着性能呢?下面尝试开启预处理来解决问题。

      开启预处理:

     1  public static int ExecuteNonQuery(string commandText, CommandType commandType)
     2         {
     3             int result = 0;
     4             if (commandText == null || commandText.Length == 0)
     5                 throw new ArgumentNullException("sql语句为空");
     6             using (SQLiteConnection con = new SQLiteConnection(connectionString))
     7             {
     8                 SQLiteCommand cmd = new SQLiteCommand();
     9                 cmd.Connection = con;
    10                 cmd.CommandText = commandText;
    11                 cmd.Prepare();//开启预处理
    12                 try
    13                 {
    14                     result = cmd.ExecuteNonQuery();
    15                 }
    16                 catch (Exception ex)
    17                 {
    18                     throw ex;
    19                 }
    20             }
    21             return result;
    22         }
    23                     
    View Code

      预处理的原理就是将一条语句先预编译到数据库,下次再次执行相同的语句时,就不用再次编译,节省了大量的时间。由此看来,代码似乎还没有优化完成。就第一版代码来说,由于批量插入的数据不尽相同,所以数据库会多次编译插入语句,性能会损耗非常多,也就造成插入需要的时间会比较多。有没有一条语句是可以循环使用的?答案是有的,使用参数化传值,就能使每一次的插入的sql语句都是相同的。

      参数化(数据库帮助类那边我就不写了):

     1 StringBuilder sql = new StringBuilder();
     2 SQLiteParameter[] sp = new SQLiteParameter[2];
     3 foreach (DataRow dr in dt.Rows)
     4 {
     5 sql.Clear();
     6 sql.Append("INSERT INTO Info (Name,Code) VALUES(@Name,@Code) 
    ");  
     7 sps[0] = new SQLiteParameter("@p1", dr["Name"]);
     8 sps[1] = new SQLiteParameter("@p2", dr["Code"]);
     9 sqlHelper.SqliteHelper.ExecuteNonQuery(sql.ToString(),sp, CommandType.Text);  
    10 }
    View Code

      经过一系列优化处理后,插入1万条数据只需要不到1秒,性能得到了极大的提升。

      另外,本人新手,如有不对,望不吝指教。

  • 相关阅读:
    天梯赛5-12 愿天下有情人都是失散多年的兄妹 【dfs】
    poj2718 Smallest Difference【贪心】
    HDU problem 5635 LCP Array【思维】
    codeforces 782C Andryusha and Colored Balloons【构造】
    HDU 4278 Faulty Odometer【进制转换】
    codeforces B. The Meeting Place Cannot Be Changed【二分】
    POJ 3264 Balanced Lineup 【线段树】
    HDU 1850
    CodeForces-714C
    HDU Problem 1247 Hat's Words 【字典树】
  • 原文地址:https://www.cnblogs.com/yisen-code/p/6897524.html
Copyright © 2011-2022 走看看