众所周知,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]+"‘) \r\n"); 5 } 6 sqlHelper.SqliteHelper.ExecuteNonQuery( sql.ToString(), CommandType.Text);
从上面的代码看来,我没有进行任何优化工作,我用这种方式插入了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]+"‘) \r\n"); 6 } 7 sql.Append("COMMIT;");//提交事务 8 sqlHelper.SqliteHelper.ExecuteNonQuery( sql.ToString(), CommandType.Text);
由于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
预处理的原理就是将一条语句先预编译到数据库,下次再次执行相同的语句时,就不用再次编译,节省了大量的时间。由此看来,代码似乎还没有优化完成。就第一版代码来说,由于批量插入的数据不尽相同,所以数据库会多次编译插入语句,性能会损耗非常多,也就造成插入需要的时间会比较多。有没有一条语句是可以循环使用的?答案是有的,使用参数化传值,就能使每一次的插入的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) \r\n"); 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 }
经过一系列优化处理后,插入1万条数据只需要不到1秒,性能得到了极大的提升。
另外,本人新手,如有不对,望不吝指教。