自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

SQLite做為本地緩存應(yīng)注意的幾大方面

數(shù)據(jù)庫 其他數(shù)據(jù)庫
今天我們要介紹的就是如何利用SQLite作為本地緩存的方法。其擁有適應(yīng)于本地?cái)?shù)據(jù)緩存和應(yīng)用程序等諸多優(yōu)點(diǎn)。

今天看到了園友陸敏計(jì)的一篇文章<<C#數(shù)據(jù)本地存儲(chǔ)方案之SQLite>>, 寫到了SQLite的諸多優(yōu)點(diǎn),尤其適應(yīng)于本地?cái)?shù)據(jù)緩存和應(yīng)用程序。

轉(zhuǎn)自陸兄的內(nèi)容,來夸夸Sqlite:

SQLite官方網(wǎng)站: http://www.sqlite. org/ 時(shí)第一眼看到關(guān)于SQLite的特性。

1. ACID事務(wù)

2. 零配置 – 無需安裝和管理配置

3. 儲(chǔ)存在單一磁盤文件中的一個(gè)完整的數(shù)據(jù)庫

4. 數(shù)據(jù)庫文件可以在不同字節(jié)順序的機(jī)器間自由的共享

5. 支持?jǐn)?shù)據(jù)庫大小至2TB

6. 足夠小, 大致3萬行C代碼, 250K

7. 比一些流行的數(shù)據(jù)庫在大部分普通數(shù)據(jù)庫操作要快

8. 簡單, 輕松的API

9. 包含TCL綁定, 同時(shí)通過Wrapper支持其他語言的綁定

10. 良好注釋的源代碼, 并且有著90%以上的測(cè)試覆蓋率

11. 獨(dú)立: 沒有額外依賴

12. Source完全的Open, 你可以用于任何用途, 包括出售它

13. 支持多種開發(fā)語言,C, PHP, Perl, Java, ASP .NET,Python

正好前一段時(shí)間我做了這方面的應(yīng)用,我就結(jié)合陸兄的這篇文章,談?wù)勎以赟qlite本地緩存業(yè)務(wù)數(shù)據(jù)時(shí)的經(jīng)驗(yàn),給大家借鑒一下。我開發(fā)時(shí)比較倉促,很多地方請(qǐng)大家多提意見。

解決的問題

首先介紹我用Sqlite解決的實(shí)際問題是什么?

問題1:某個(gè)功能的數(shù)據(jù)需要連接一個(gè)遠(yuǎn)程數(shù)據(jù)庫查詢速度很慢,查一次數(shù)據(jù)不容易,希望能夠重復(fù)利用之前查過的數(shù)據(jù)集。

問題2:非常大的數(shù)據(jù)量比如幾千萬甚至幾億條數(shù)據(jù),一次性讀取到DataTable中,會(huì)內(nèi)存溢出的,所以在第一次分析時(shí)就是通過Reader的方式,分析完一條后并不在內(nèi)存中保存,但是緊接著用戶的第二次分析、第三次分析還是要用到的第一次分析的數(shù)據(jù),如果我們重新查詢一次遠(yuǎn)程服務(wù)器,效率可想而知啊。

結(jié)合上面的2個(gè)問題,為了解決效率問題和數(shù)據(jù)重復(fù)利用度,減少數(shù)據(jù)庫服務(wù)器的壓力,我才用Sqlite緩存數(shù)據(jù)(當(dāng)然這不是唯一也不是最好的解決方案) 。

優(yōu)化SQLiteHelper

陸兄的SQLiteHelper類我增加了幾個(gè)有用的方法:

第一個(gè)方法是GetSchema,得到某個(gè)表的表結(jié)構(gòu)。

  1. /// <summary>     
  2. /// 查詢數(shù)據(jù)庫中的所有數(shù)據(jù)類型信息     
  3. /// </summary>     
  4. /// <returns></returns>     
  5. public DataTable GetSchema()  
  6. {  
  7.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  8.     {  
  9.         connection.Open();  
  10.         DataTable data = connection.GetSchema("TABLES");  
  11.         connection.Close();  
  12.         //foreach (DataColumn column in data.Columns)     
  13.         //{     
  14.         //    Console.WriteLine(column.ColumnName);     
  15.         //}     
  16.         return data;  
  17.     }  

第二個(gè)方法是IsTableExist,判斷SQLite數(shù)據(jù)庫重某個(gè)表是否存在 。

  1. /// <summary>     
  2. /// 判斷SQLite數(shù)據(jù)庫表是否存在    
  3. /// </summary>     
  4. /// <param name="dbPath">要?jiǎng)?chuàng)建的SQLite數(shù)據(jù)庫文件路徑</param>     
  5. public bool IsTableExist(string tableName)  
  6. {  
  7.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  8.     {  
  9.         connection.Open();  
  10.         using (SQLiteCommand command = new SQLiteCommand(connection))  
  11.         {  
  12. command.CommandText = "SELECT COUNT(*) FROM sqlite_master where type='table' and name='" + tableName + "'";  
  13.             int iaaa = Convert.ToInt32(command.ExecuteScalar());  
  14.             if (Convert.ToInt32(command.ExecuteScalar()) == 0)  
  15.             {  
  16.                 return false;  
  17.             }  
  18.             else  
  19.             {  
  20.                 return true;  
  21.             }  
  22.         }  
  23.     }  

第三個(gè)方法是Query,執(zhí)行查詢語句,返回DataSet

  1. /// <summary> 
  2. /// 執(zhí)行查詢語句,返回DataSet  
  3. /// </summary> 
  4. /// <param name="SQLString">查詢語句</param> 
  5. /// <returns>DataSet</returns> 
  6. public DataSet Query(string SQLString)  
  7. {  
  8.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  9.     {  
  10.         DataSet ds = new DataSet();  
  11.         try  
  12.         {  
  13.             connection.Open();  
  14.             SQLiteDataAdapter command = new SQLiteDataAdapter(SQLString, connection);  
  15.             command.Fill(ds, "ds");  
  16.         }  
  17.         catch (System.Data.SQLite.SQLiteException ex)  
  18.         {  
  19.             throw new Exception(ex.Message);  
  20.         }  
  21.         return ds;  
  22.     }  

構(gòu)建緩存對(duì)象模型和緩存控制器

每一塊緩存對(duì)象,在數(shù)據(jù)庫中會(huì)產(chǎn)生一個(gè)表,而表名稱是有緩存控制器自動(dòng)生成的,訪問緩存的工作全部交由緩存控制器完成,通過緩存項(xiàng)的ID和ModuleKey來訪問。

在Sqlite中還需要一個(gè)系統(tǒng)表來維護(hù)每個(gè)緩存項(xiàng)和實(shí)際緩存存儲(chǔ)表之間的對(duì)應(yīng)關(guān)系,我們稱之為配置表,它將在緩存控制器創(chuàng)建Sqlite緩存數(shù)據(jù)庫文件時(shí)創(chuàng)建。

配置表共有以下幾個(gè)字段,分別和緩存對(duì)象模型CdlCacheItem類映射:

列名稱 說明
Id 緩存的唯一數(shù)字編號(hào)
ModuleKey 緩存模塊名稱,一個(gè)模塊可以有多個(gè)緩存數(shù)據(jù),ID可以區(qū)分。實(shí)際應(yīng)用時(shí),某個(gè)功能時(shí)會(huì)經(jīng)常緩存數(shù)據(jù)的,所以通過ModuleKey就可以得到這個(gè)功能所有的緩存列表,然后選定其中的部分緩存來進(jìn)行使用。
Comments 緩存說明
TableName 緩存數(shù)據(jù)存儲(chǔ)的數(shù)據(jù)表名稱
AddDate 緩存時(shí)間戳

創(chuàng)建數(shù)據(jù)庫的方法如下

  1. static void CreateDB()  
  2. {  
  3.     //總共有ID、ModuleKey、Comments、AddDate這幾列  
  4.     string sql = "CREATE TABLE SYSCDLTABLES(ID 
  5. INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,MODULEKEY VARCHAR(200),
  6. COMMENTS VARCHAR(500),TABLENAME VARCHAR(100),ADDDATE DATETIME)";  
  7.     SQLiteDBHelper.CreateDB(CACHEFILEPATH, sql);  

每個(gè)緩存項(xiàng)(緩存對(duì)象模型)定義如下,和配置表對(duì)應(yīng):

  1. /// <summary> 
  2. /// 緩存項(xiàng)對(duì)象  
  3. /// </summary> 
  4. /// <Author>Tecky Lee</Author> 
  5. /// <Date>2011-1-11 15:11</Date> 
  6. public class CdlCacheItem  
  7. {  
  8.     int m_id;  
  9.  
  10.     public int Id  
  11.     {  
  12.         get { return m_id; }  
  13.         set { m_id = value; }  
  14.     }  
  15.     string m_moduleKey;  
  16.  
  17.     public string ModuleKey  
  18.     {  
  19.         get { return m_moduleKey; }  
  20.         set { m_moduleKey = value; }  
  21.     }  
  22.     string m_comments;  
  23.  
  24.     public string Comments  
  25.     {  
  26.         get { return m_comments; }  
  27.         set { m_comments = value; }  
  28.     }  
  29.     string m_tableName;  
  30.  
  31.     public string TableName  
  32.     {  
  33.         get { return m_tableName; }  
  34.         set { m_tableName = value; }  
  35.     }  
  36.     DateTime m_timestamp;  
  37.  
  38.     public DateTime Timestamp  
  39.     {  
  40.         get { return m_timestamp; }  
  41.         set { m_timestamp = value; }  
  42.     }  

下面是控制器的接口定義:

  1. public interface ICdlCacheController  
  2.     {  
  3.         void BeginLoadRow();  
  4.         void EndLoadRow();  
  5.         System.Collections.Generic.IList<CdlCacheItem> GetCdlCacheItems(string moduleKey);  
  6.         CdlCacheItem GetCdlCacheItems(int id);  
  7.         void LoadRow(System.Data.DataRow row, string tableName);  
  8.         void LoadRow(IEnumerable<object> row, string tableName);  
  9.         string LoadTable(System.Data.DataTable dt, string moduleKey, string comments);  
  10.         System.Data.Common.DbDataReader QueryCdlTableReader(CdlCacheItem item);  
  11.         System.Data.DataTable QueryCdlTables(CdlCacheItem item);  
  12.         System.Data.DataTable QueryCdlTables(string sql);  
  13.         void RemoveAllTables();  
  14.         void RemoveCdlTables(string moduleKey);  
  15.         void RemoveCdlTables(System.Collections.Generic.IList<CdlCacheItem> items);  
  16.         void RemoveCdlTables(CdlCacheItem item);  
  17.         void RemoveCdlTables(int id);  
  18.     } 

上面的函數(shù)下面來做個(gè)說明:

1、BeginLoadRow、LoadRow和EndLoadRow,三個(gè)函數(shù)組為了在我們查詢主數(shù)據(jù)庫時(shí)使用Reader方式讀取數(shù)據(jù)時(shí),可以一條條將數(shù)據(jù)同時(shí)存放在緩存中。

2、RemoveAllTables和RemoveCdlTables是用來刪除緩存項(xiàng)的。

3、GetCdlCacheItems,通過moduleKey得到多個(gè)緩存項(xiàng)。比如用戶想基于這幾天內(nèi)保存的某個(gè)功能的數(shù)據(jù)做一次快速分析,那么我們就可以通過這個(gè)函數(shù)得到緩存列表,由用戶選擇列表中的一個(gè)來繼續(xù)。

4、QueryCdlTableReader,得到某個(gè)緩存數(shù)據(jù)的Reader對(duì)象,這樣可以一行行的分析,一次讀出大數(shù)據(jù)量的數(shù)據(jù)到DataTable中,內(nèi)存可能會(huì)溢出的。

5、QueryCdlTables,將某個(gè)緩存項(xiàng)查詢并裝載到DataTable中。

提高緩存數(shù)據(jù)寫入效率

Sqlite在保存數(shù)據(jù)的時(shí)候,比如一次保存一個(gè)億條的數(shù)據(jù),一條條插入效率非常低下,網(wǎng)上也有人對(duì)其進(jìn)行討論。

效率低下的主要原因在于IO操作次數(shù)過于頻繁,所以在LoadTable或者是使用BeginLoadRow·EndLoadRow的時(shí)候,使用了事務(wù)來減少數(shù)據(jù)提交的次數(shù),結(jié)果保存的效率非常的高,我測(cè)試的結(jié)果是400萬條數(shù)據(jù)查詢,只需要幾十秒鐘,這點(diǎn)時(shí)間相對(duì)于重新查一次遠(yuǎn)程服務(wù)器那是可以忽略了。

下面給出BeginLoadRow和EndLoadRow的具體代碼(只有在EndRow的時(shí)候才會(huì)提交一次數(shù)據(jù)):

  1. SQLiteConnection m_connection;  
  2. SQLiteCommand m_command;  
  3. DbTransaction m_transaction;  
  4. public void BeginLoadRow()  
  5. {  
  6.     m_connection = new SQLiteConnection("Data Source=" + CACHEFILEPATH);  
  7.  
  8.     m_connection.Open();  
  9.     m_transaction = m_connection.BeginTransaction();  
  10.     m_command = new SQLiteCommand(m_connection);  
  11. }  
  12. public void EndLoadRow()  
  13. {  
  14.     try  
  15.     {  
  16.         if (m_command != null)  
  17.             m_command.Dispose();  
  18.  
  19.         if (m_transaction != null)  
  20.         {  
  21.             m_transaction.Commit();  
  22.         }  
  23.  
  24.         if (m_connection != null)  
  25.         {  
  26.             m_connection.Close();  
  27.             m_connection.Dispose();  
  28.         }  
  29.     }  
  30.     catch (System.Exception ex)  
  31.     {  
  32.         LogHandle.Error(ex);  
  33.     }  

LoadTable函數(shù)內(nèi)部也是調(diào)用BeginLoadRow·EndLoadRow模式來完成的。

數(shù)據(jù)庫文件如何創(chuàng)建:

Sqlite數(shù)據(jù)庫文件如果不存在,在執(zhí)行sql語句的時(shí)候,會(huì)自動(dòng)根據(jù)ConnetionString中指定的位置創(chuàng)建數(shù)據(jù)庫文件,默認(rèn)創(chuàng)建的空數(shù)據(jù)庫只有4K。

其他有待討論的問題:

1、我是將所有的緩存做到一個(gè)數(shù)據(jù)庫文件中了,實(shí)際應(yīng)用根據(jù)業(yè)務(wù)的不同,可以一份緩存數(shù)據(jù)一個(gè)文件也是很好管理的,維護(hù)也方便,資源管理器中就可以拷貝刪除等。

2、當(dāng)我們存儲(chǔ)一億條數(shù)據(jù)到Sqlite的時(shí)候,因?yàn)镾qlite沒有壓縮數(shù)據(jù),結(jié)果數(shù)據(jù)庫文件就可以會(huì)有好幾個(gè)G(這也不一定,適合數(shù)據(jù)庫字段的多少,字段類型有關(guān)的)。

文件太大就消耗了磁盤空間,而且用戶或者程序如果不及時(shí)清理的,可能會(huì)耗盡磁盤空間。

這里就必須建立一個(gè)機(jī)制,檢查sqlite的緩存并及時(shí)清理,或者設(shè)置緩存應(yīng)用的上限,當(dāng)達(dá)到上限后自動(dòng)根據(jù)時(shí)間戳清理歷史緩存。

原文鏈接:http://www.cnblogs.com/TeckyLi/archive/2011/02/17/1957317.html

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2010-09-25 13:51:46

2011-07-03 23:27:01

SEO

2010-09-26 15:37:34

制定數(shù)據(jù)加密項(xiàng)目

2010-09-27 14:18:34

2011-04-29 12:54:00

筆記本

2015-04-22 15:14:38

JavaScriptJavaScript數(shù)

2011-03-09 09:24:18

2009-10-12 15:56:31

綜合布線系統(tǒng)線纜

2018-07-04 05:51:04

弱電系統(tǒng)線路故障

2010-03-01 14:13:06

2018-09-13 22:49:36

數(shù)據(jù)中心機(jī)房網(wǎng)絡(luò)

2011-04-01 15:09:56

Java

2016-03-17 09:46:53

2009-07-16 10:35:34

iBATIS特性

2011-11-14 09:58:33

2020-03-22 11:04:33

ITOps安全IT運(yùn)營安全IT安全

2013-01-07 15:05:09

2010-04-27 16:54:11

Oracle RAC

2010-04-02 16:31:58

Oracle RAC

2010-04-23 16:04:48

Oracle查詢優(yōu)化
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)