SQLite - 我所認識的數據庫引擎


SQLite 是一款輕量級的、被設計用於嵌入式系統的關聯式數據庫管理系統。SQLite 是一個實現自我依賴、純客戶端、零配置且支持事務的數據庫引擎。它由D. Richard Hipp首次開發,目前已是世界上最廣泛部署的開源數據庫引擎。

  本文中,我們將介紹如下內容:

創建一個SQLite 數據庫

SQLiteConnection conn = new SQLiteConnection("Data Source=mytest.s3db");
conn.Open();

SQLite 數據插入

/// <summary>
///     Allows the programmer to easily insert into the DB
/// </summary>
/// <param name="tableName">The table into which we insert the data.</param>
/// <param name="data">A dictionary containing the column names and data for the insert.</param>
/// <returns>A boolean true or false to signify success or failure.</returns>
public bool Insert(string tableName, Dictionary<string, string> data)
{
    Boolean returnCode = true;
    StringBuilder columnBuilder = new StringBuilder();
    StringBuilder valueBuilder = new StringBuilder();
    foreach (KeyValuePair<string, string> val in data)
    {
        columnBuilder.AppendFormat(" {0},", val.Key);
        valueBuilder.AppendFormat(" '{0}',", val.Value);
    }
    columnBuilder.Remove(columnBuilder.Length - 1, 1);
    valueBuilder.Remove(valueBuilder.Length - 1, 1);
    try
    {
        this.ExecuteNonQuery(string.Format("INSERT INTO {0}({1}) VALUES({2});", 
            tableName, columnBuilder, valueBuilder));
    }
    catch (Exception ex)
    {
        mLog.Warn(ex.ToString());
        returnCode = false;
    }
    return returnCode;
}
for (int i = 0; i <= ROWS4ACTION; i++)
{
    insertParameterDic.Clear();
    DateTime entryTime;
    string name = string.Empty, title = string.Empty;
    GetSampleData(out name, out title, out entryTime);
    int id = random.Next();
    insertParameterDic.Add("Id", id.ToString());
    insertParameterDic.Add("Name", name);
    insertParameterDic.Add("Title", title);
    insertParameterDic.Add("EntryTime",
        entryTime.ToString("yyyy-MM-dd HH:mm:ss"));

    db.Insert("Person", insertParameterDic);
}

SQLite 的事務處理方式

Begin Transaction:

begin-stmt

Commit Transaction:

commit-stmt

Rollback Transaction:

rollback-stmt

try
{
    db.OpenTransaction();
    Insert4Native();
    db.CommiteTransaction();
}
catch (System.Exception ex)
{
    mLog.Error(ex.ToString());
    db.RollbackTransaction();
}

SQLite 的索引

索引是一種用來優化查詢的特性,在數據中分為聚簇索引和非聚簇索引;前者是由數據庫中數據組織方式決定的,比如我們在往數據庫中一條一條插入數據時,聚簇索引能夠保證按順序插入,插入后數據的位置和結構不變。非聚簇索引是指我們手動、顯式創建的索引,可以為數據庫中的每個列創建索引,和字典中的索引類似,遵循的原則是對有分散性和組合型的列建立索引,以利於大數據和復雜查詢情況下提高查詢效率。

create-index-stmt

/// <summary>
/// Create index
/// </summary>
/// <param name="tableName">table name</param>
/// <param name="columnName">column name</param>
/// <param name="indexName">index name</param>
public void CreateIndex(string tableName, string columnName, string indexName)
{
    string createIndexText = string.Format("CREATE INDEX {0} ON {1} ({2});", 
        indexName, tableName, columnName);
    ExecuteNonQuery(createIndexText);
}

簡單查詢無關數據庫大小情況下對查詢效率的測試結果如下(700,000條數據):

string sql = "SELECT LeafName FROM File WHERE Length > 5000";

Capture

復雜查詢情況下對查詢效率的測試結果如下(~40,000條數據):

string sql = "SELECT folder.Location AS FilePath" 
    + "FROM Folder folder LEFT JOIN File file ON file.ParentGuid=folder.Guid" 
    +"WHERE file.Length > 5000000 GROUP BY File.LeafName";

Capture2

SQLite 的觸發器(Trigger)

觸發器是指當一個特定的數據庫事件(DELETE, INSERT, or UPDATE)發生以后自動執行的數據庫操作,  我們可以把觸發器理解為高級語言中的事件(Event)。

  假設我有兩個表:

Folder(Guid VCHAR(255) NOT NULL, Deleted BOOLEAN DEFAULT 0)

File(ParentGuid VCHAR(255) NOT NULL, Deleted BOOLEAN DEFAULT 0)

在Folder 表中創建一個觸發器Update_Folder_Deleted:

CREATE TRIGGER Update_Folder_Deleted UPDATE Deleted ON Folder
  Begin
    UPDATE File SET Deleted=new.Deleted WHERE ParentGuid=old.Guid; 
  END;

創建完觸發器以后在執行以下語句:

UPDATE Folder SET Deleted=1 WHERE Guid='13051a74-a09c-4b71-ae6d-42d4b1a4a7ae'

以上語句將會導致下面的語句自動執行:

UPDATE File SET Deleted=1 WHERE ParentGuid='13051a74-a09c-4b71-ae6d-42d4b1a4a7ae'

SQLite 的視圖(View)

視圖可以是一個虛擬表,里面可以存儲按照一定條件過濾出來的數據集合,這樣我們再下次想得到這些特定數據集合的時候就不用通過復雜查詢來獲得,簡單的查詢指定視圖就可以得到想要的數據。

在下個例子中,我們創建一個簡單的視圖:

Capture

基於上面的查詢結果我們創建一個視圖:

Capture2

SQLite 命令行工具

SQLite 庫中包含了一個SQLite3.exe 的命令行工具,它可以實現SQLite 各項基本操作。這里只介紹一下如何使用它來分析我們的查詢結果:

1. CMD->sqlite3.exe MySQLiteDbWithoutIndex.s3db

Capture

2. 開啟EXPLAIN 功能並分析指定查詢結果

Capture

3. 重新使用命令行打開一個有索引的數據庫並執行前兩步

Capture

4. 通過比較兩個不同查詢語句的分析結果,我們可以發現如果查詢過程中使用了索引,SQLite 會在detail 列中提示我們。

5. 要注意的是每條語句后面都要加分號“;”

SQLite一些常見的使用限制

1. SQLite 不支持Unicode 字符的大小寫比較。

2. 如何處理SQLite 轉義字符:

INSERT INTO xyz VALUES('5 O''clock');

3. 一條復合SELECT語句的條數限制:

  一條復合查詢語句是指多條SELECT語句由 UNION, UNION ALL, EXCEPT, or INTERSECT 連接起來. SQLite進程的代碼生成器使用遞歸算法來組合SELECT語句。為了降低堆棧的大小,SQLite 的設計者們限制了一條復合SELECT語句的條目數量。 SQLITE_MAX_COMPOUND_SELECT的默認值是500. 這個值沒有嚴格限制,在實踐中,幾乎很難看到一條復合查詢語句的條目數大於500的。

  這里提到復合查詢的原因是我們可以使用它來幫助我們快速插入大量數據:

public void Insert4SelectUnion()
{
    bool newQuery = true;
    StringBuilder query = new StringBuilder(4 * ROWS4ACTION);
    for (int i = 0; i < ROWS4ACTION; i++)
    {
        if (newQuery)
        {
            query.Append("INSERT INTO Person");
            newQuery = false;
        }
        else
        {
            query.Append(" UNION ALL");
        }

        DateTime entryTime;
        string name = string.Empty, title = string.Empty;
        GetSampleData(out name, out title, out entryTime);
        int id = random.Next();
        query.AppendFormat(" SELECT '{0}','{1}','{2}','{3}'", 
            id, name, title, entryTime.ToString("yyyy-MM-dd HH:mm:ss"));
        if (i % 499 == 0)
        {
            db.ExecuteNonQuery(query.ToString());
            query.Remove(0, query.Length);
            newQuery = true;
        }
    }

    //executing remaining lines
    if (!newQuery)
    {
        db.ExecuteNonQuery(query.ToString());
        query.Remove(0, query.Length);
    }
}

參考文檔

http://www.sqlite.org/lang_createindex.html

http://ch-werner.de/sqliteodbc/

http://zetcode.com/databases/sqlitetutorial/viewstriggerstransactions/

http://www.sqlite.org/faq.html

http://www.sqlite.org/eqp.html

http://www.sqlite.org/lang_createtrigger.html

https://developer.appcelerator.com/question/104531/sqlite-multiple-insert


免責聲明!

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



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