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]+"') \r\n");    
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]+"') \r\n");    
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) \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 }
View Code

  經過一系列優化處理后,插入1萬條數據只需要不到1秒,性能得到了極大的提升。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM