• 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


    作者:DanielWise
    出处:http://www.cnblogs.com/danielWise/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    想起来好久没更新博客了
    操作系统文件管理
    PreparedStatement是如何大幅度提高性能的
    Java中快速排序的实现
    详解HashMap的内部工作原理
    关于Java集合的总结
    浅谈JVM内存区域划分
    解决java压缩图片透明背景变黑色的问题
    Vmware15.5中centos7minimal版 窗口字体太小
    字符长度还是字节长度
  • 原文地址:https://www.cnblogs.com/danielWise/p/2843585.html
Copyright © 2020-2023  润新知