天天看點

SQLite 批量insert - 如何加速SQLite的插入操作

本人翻譯, 原文見:

http://tech.vg.no/2011/04/04/speeding-up-sqlite-insert-operations/

我正在開發一個Android程式, 它使用SQLite存儲大約6000行的資料, 這些資料會定期從網上更新. 在模拟器上, 從網絡擷取和解析CSV格式的資料所花的時間大概是20秒, 但是把資料插入的資料庫的時間是71秒.

因為資料更新的操作差不多一個星期才有一次, 是以我認為1分多鐘的操作時間是可以接受的. 但當我把程式在真機上跑的時候, 6000行的插入時間讓我吓了一跳 -- 478秒, 差不多8分鐘. 很奇怪, 一般來說, 真機要比模拟器快, 何況我用的是Sanmsung Galaxy S - 當時最快的Android裝置之一. 這是我第一次使用SQLite, 我想我下一步得優化插入操作了.

Sql代碼  

SQLite 批量insert - 如何加速SQLite的插入操作

  1. String sql = "INSERT INTO table (number, nick) VALUES (?, ?)";  
  2. SQLiteStatement stmt = db.compileStatement(sql);  
  3. for (int i = 0; i < values.size(); i++) {  
  4.     stmt.bindString(1, values.get(i).number);  
  5.     stmt.bindString(2, values.get(i).nick);  
  6.     stmt.execute();  
  7.     stmt.clearBindings();  
  8. }  

有了上面的改動後, 我在模拟器上測試, 時間從71秒減少到56秒, 但是在真機上測的時候, 時間反而多了幾秒, 我反複測了幾次, 還是差不多一樣的結果.

進一步研究, 我從SQLite的一個文檔頁面看到“PRAGMA synchronous = OFF” 将會告訴SQLite, 當它把資料傳入作業系統的時候, 不要立即同步. 這個設定讓插入時間從71秒減少的50秒, 在真機上的結果是361秒, 差不多快2分鐘.

感覺到找到路子之後, 我認為是檔案系統減慢了插入操作, 我在網上找到了很多關于Galaxy S I/O 性能問題的參考 - 所有的都與RFS檔案系統相關. 對于SQLite而言, 它每插入一次資料, 都會執行一下fsync, 以保證資料寫入了磁盤. 再看SQLite文檔, 我發現用transactions能夠将資料儲存在記憶體中, 隻有在commit時候才寫入檔案系統. 是以我改動如下:

Java代碼  

SQLite 批量insert - 如何加速SQLite的插入操作
  1. db.beginTransaction();  
  2. db.setTransactionSuccessful();  
  3. db.endTransaction();  

結合transactions和 compiled statements後, 性能有了巨大的提升: 從71秒到不可置信的5秒! 在Galaxy上的結果更是牛逼: 從478秒到1.5秒!

結論:

- 除非你隻執行單次的insert, 或者你需要資料立即寫入檔案系統, 不然的話就用transactions

- 保證你的程式在真機上測試過, 最好是多台機器上測.

- 我上面的性能提升隻在Samsung Galaxy S上測過, 不同的機器可能還是會有性能問題.