简单分析SQLite4的一些设计改变

1.0 内容提要

SQLite4 是一个放在库中的紧凑的,自包含的,零维护的的ACID数据库引擎, 像SQLite3一样, 但具有改进的接口和文件格式.

运行时环境封装到了一个对象之中.

使用了一个很不错的键值对存储引擎:

  • 一个独立的大型键空间 - 不是SQLite3中那种每个表单独的键空间和索引.
  • 按字典顺序的键排序.
  • 多个存储引擎,可在运行时互换.
  • 默认在磁盘上的存储殷勤使用了一个日志结构的合并数据库.

表的PRIMARY KEY真正被用作存储引擎的键.

可以使用小数点运算.

外键约束和递归触发器默认是启用的.

覆盖指数可以显示声明.

2.0 概述

SQLite4 对于SQLite3而言,是一个可选方案,而不是一个替代方案. SQLite3 还没有过时. SQLite3 和 QLite4 将会并行受到支持. SQLite3 遗留的好处不会被抛弃.   SQLite3 还将会被持续的维护和改进. 但如果需要的话,新系统的设计者现在将可以选择 SQLite4 而不是 SQLite3.

SQLite4 努力保持了SQLite3的最优秀特性,同时在不破坏兼容性的前提下解决了SQLite3中无法修复的问题. SQLite3 和 SQLite4 中将会持续保持一样的特性有:

  • SQLite4 是放在一个库中并链接到一个大型应用程序的完整的,关系型,事务性的, ACID, SQL 数据库引擎.  没有服务器,I/O直接面向硬盘.
  • SQLite4 的源代码任何人可以用于任何目的.  没有版权、发布或者公开源代码或者编译二进制文件方面的的限制.  不用去担心烦人的许可证.
  • 使用了动态类型,而不是大多数其它的SQL数据库引擎所使用的僵化的静态类型.
  • (默认)在磁盘上的镜像是一个单独的使用良好且稳定文件格式的磁盘文件, 使得SQLite4库适合于作为一个应用程序的文件格式使用.
  • SQLite4 将会是快速且可靠的,无需管理员操心它就能运作的蛮好.
  • SQLite4 的实现只有最简化的依赖,因而它可以很容易的集成到嵌入式系统或者其它非常规的运行时环境.

实现上仍然采用常用的汇编语言C。与SQLite3相比,SQLite4使用了更多C99特性,不过仍然可以使用常见的编译器编译。SQLite4使用了诸如size_t,int64_t,uint64_t以及其他标准数据类型。

SQLite4的编程接口与SQLite3的非常相似,只不过命名前缀都从sqlite3_更改为sqlite4_。SQLite3中旧的和作废的接口已经从SQLite4中剔除了。给一些函数增加了参数,有时对参数稍作修改或者对其参数顺序进行重新排序。修改了某些接口名字,使其更加符合其功能。总体上来说,SQLite4的编程接口与SQLite3的非常相似,这样移植一个SQLite3上的应用到SQLite4上只需花一个小时或者两个小时完成搜索替代就可以了。

SQLite3和SQLite4没有共用任何符号,因此把SQLite3和SQLite4同时嵌入到同一进程,同时使用它们都是可行的.

3.0 SQLite4的主要改变
3.1 运行时对象

SQLite4中一些接口的第一个参数接收一个(新加的)指向一个sqlite4_env对象的指针,它定义了运行时环境。需要接收sqlite4_env指针的示例程序包括:

  • sqlite4_open()
  • sqlite4_malloc(), sqlite4_realloc(), and     sqlite4_free()
  • sqlite4_mprintf()
  • sqlite4_random()
  • sqlite4_config()

一个sqlite4_env对象实例定义了SQLite4与其他系统交互是如何交互的。一个sqlite4_env对象包含的方法能够:

  • 分配,进入,离开和收回互斥体
  • 分配,调整和释放堆内存,
  • 访问和控制底层键/值存储引擎,
  • 使用高质量随机种子初始化内建PRNG,
  • 取得当前时间和日期与本地时区,
  • 记录error日志消息.

标准平台(windows和Unix)的SQLite4构建包含了一个全局sqlite4_env对象,通常这个对象适配于所在平台。如果一个接口程序的参数中有一个指向sqlite4_env对象的指针,而且传给这个参数的指针是空指针时,这个接口程序就会使用默认的全局sqlite4_env对象。另外,某些应用可能要求在相同的地址空间上运行两个或者多个SQLite4实例,同时每个实例使用了各自不同的互斥原语,不同的内存堆以及不同的时间日期函数等等。SQLite4通过对每个数据库实例创建不同的sqlite4_env对象来满足这种需求。sqlite4_env对象中还废除了全局和静态变量,这样就可以非常容易地把SQLite4移植到哪些对静态或者全局数据提供有限支持的嵌入式系统中。

3.2 简化的键/值存储引擎

相对于SQLite3,SQLite4使用的键/值存储引擎拥有一个大大简化了的接口。这个存储引擎是可拔插的;通过对qlite4_env对象在打开新的数据库连接前做适当的改动,它可以在运行时被改变。

SQLite4 需要一个实现了有序键/值对的存储引擎,它的键和值是任意长度的二进制数据。键必须惟一,且按字典排序。也就是说,键应该根据一个比较函数进行排序,例如:
 

代码如下:

int key_compare(const void *key1, int n1, const void *key2, int n2){
  int c = memcmp(key1, key2, n1<n2 ? n1 : n2);
  if( c==0 ) c = n1 - n2;
  return c;
}

给定一个探针键,SQLite4需要能够找到它最近的键,然后以字典序升序或降序遍历键。向一个已有的键插入数据时会覆盖旧数据。事务,包括原子提交和回滚,由存储引擎负责。

SQLite4经由表和索引,将所有数据存储到一个单独的键空间, 与此相反,SQLite3中每个表和索引都需要一个单独的键空间。SQLite4的存储也与SQLite3不同,因为它需要存储引擎以字典序对键进行排序, 而SQLite3使用了一个非常复杂的比较函数来决定记录的存储顺序。

SQLite4与存储引擎之间的通信是通过一个定义完善的并且简单的接口进行的。新的存储引擎可以在运行期间进行替换:只要在指定数据库连接之前替换sqlite4_env对象里的某些函数指针就可以了。

如果替换的存储引擎不支持回滚,那么这就意味着SQLite4无法运行ROLLBACK。如果替换的存储引擎不支持事务嵌套,那么这就意味着SQLite4无法运行嵌套事务。因此,嵌入到SQLite4中的存储引擎的功能越少,对应的整体的系统功能就会越差。

默认情况下内置的存储引擎是日志结构的合并式数据库。它比LevelDB要快很多倍,支持嵌套式事务,它把整个内容存储在单一的磁盘文件里。SQLite4的未来版本还可能包含一个内置的采用B树结构的存储引擎。

3.3 现在的PRIMARY KEY是真正的主键

Sqlite3允许声明表中的任何单个或多列为主键。但在内部,SQLite3只将PRIMARY KEY简单地当做唯一约束来对待。实际中用于存储使用的键是每一行的rowid。

Sqlite4则相反,它真实地使用声明的表主键(更确切地说是PRIMARY KEY的编码值)作为键而插入存储引擎。SQLite4表通常没有rowid(除非在表没有PRIMARY KEY的情况下,这时需要一个rowid作为隐式主键。)这意味着内容在磁盘中按主键的顺序存储。这也意味着可以通过对PRIMARY KEY的一次查询即可定位记录。在SQLite3中,主键上的一个搜索意味着在自动创建的索引中先找到rowid,然后依据该rowid对主表做一个二次搜索。

SQLite4 需要 PRIMARY KEY 的所有元素不能为空. 这是一条SQL标准.  由于早期版本的疏忽, SQLite3 没有在PRIMARY KEY 列上强制加上这条NOT NULL约束,到该漏洞被发现的时候SQLite3已经在被广泛使用了, NOT NULL 约束的激活就可能会对太多的程序造成影响.
3.4 十进制数

SQLite4 使用十进制算数做所有的数字计算. SQLite4 从不使用C类型的double或者float(除了在double和内部十进制表示之间转换时使用语接口例程中).  相反,所有数字值在内部表示方式为一个带有3位数字的基于10的指数的18位十进制数.  这一表示方式的特性有:

  • 即使是在缺乏对于IEEE 754 binary64浮点数字支持的平台上,其运作起来也是可靠和兼容的.
  • 货币计算通常可以精确的进行,不需要四舍五入.
  • 任何有符号和无符号的64位整数都能被精确的表示.
  • 浮点数范围和精确度超出了 IEEE 754 binary64 浮点数.
  • 正无穷和负无穷以及 NaN (Not-a-Number) 都有良好的表示方式.

SQLite4 使得整型和浮点型数字之间没有了差别. 不过期却有精确和近似数之间的分别. 在 C/C++ 中, 整形数是精确的而浮点数是近似的. 但SQLite4并不一定如此.  浮点数字在SQLite4可以是精确的.  可以用64位表示的整型数在SQLite4中总是精确的,而大型的整型数则可能是近似的.

SQLite4 数字格式是面向内部使用的.  数字可以在整型和double型之间转换,用于输入和输出.  磁盘上的存储空间需要从1到12位的SQLite4数字值, 这取决于其大小和重要的位数.

3.5 外键约束和递归触发器是默认开启的

外键约束在SQLite3的早期版本中是没有的,并且他们默认关闭了向后兼容的能力。但是外键约束一直是有效的,并且在SQLite4中是默认打开的。所有的外键约束都是默认延迟的,尽管他们能够被定义成立即创建。但是,没有有效的机制去触发外键约束,不管是延迟创建还是立即创建。

SQLite3提供了递归触发器,但是这只是在一个运行时才有效的功能。在SQLite4中,所有的触发器在所有的时间段里都是递归的。

3.6 明确的索引覆盖

SQLite4 像 CREATE TABLE 语句中条件了一个可选的子句,该子句定义了在索引中重复的附加列信息. 这可以让应用程序开发者在SQLite4中无需使用任何花招就可以明确地创建覆盖索引.  例如:

CREATE INDEX cover1 ON table1(a,b) COVERING(c,d);

上面的 cover1 索引可以在存储引擎中用一个单一的查找操作来进行形式如 "SELECT c,d FROM table1 WHERE a=?1 AND b=?2" 的查询.  索引中如果没有附加的 COVERING 子句, SQLite4 也许会在存储引擎中做两次操作; 一次操作基于a和b的值来找到主键,而第二次操作则基于主键来找到c和d的值. COVERING 子句使得c和d的值在索引中就可用,这意味着它们无需第二次查找就可以从索引中提取出来.

COVERING 语句上有一个变化:

CREATE INDEX cover2 ON table(x,y) COVERING ALL;

COVERING ALL 语句的意思是数据表的所有列都在索引中被重复一份,这就确保了原来的数据表永远也不会被访问到,以完成一个使用了这个索引的查询.  这种方法的缺点,当然就是信息重复,而且因此让数据库文件更大.  但是通过在索引指标上明确指定COVERING关闭,SQLite4可以让应用程序开发者权衡着从应用程序中腾出空间和时间来让其更加适用.

(0)

相关推荐

  • 详解SQLite中的查询规划器

     1.0 介绍 查询规划器的任务是找到最好的算法或者说"查询计划"来完成一条SQL语句.早在SQLite 3.8.0版本,查询规划器的组成部分已经被重写使它可以运行更快并且生成更好的查询计划.这种重写被称作"下一代查询规划器"或者"NGQP". 这篇文章重新概括了查询规划的重要性,提出来一些查询规划固有的问题,并且概括了NGQP是如何解决这些问题. 我们知道的是,NGQP(下一代查询规划器)几乎总是比旧版本的查询规划器好.然而,也许有的应用程序在

  • SQLite快速入门指南

    1. 介绍 SQLite 是一个开源的嵌入式关系数据库,实现自包容.零配置.支持事务的SQL数据库引擎. 其特点是高度便携.使用方便.结构紧凑.高效.可靠. 与其他数据库管理系统不同,SQLite 的安装和运行非常简单,在大多数情况下 - 只要确保SQLite的二进制文件存在即可开始创建.连接和使用数据库.如果您正在寻找一个嵌入式数据库项目或解决方案,SQLite是绝对值得考虑. 2. 安装 SQLite on Windows 进入 SQL 下载页面:http://www.sqlite.org/

  • 详解SQLite中的数据类型

    大多数 SQL 数据库引擎 (据我们所知,除 SQLite 之外的所有 SQL 数据库引擎)都使用严格的静态类型.使用静态类型,值的类型便由它的容器 -- 存储值的特定的列 -- 来决定. SQLite 使用更通用的动态类型系统.在 SQLit 中,值的数据类型与值本身相关,而不是与它的容器.SQLite 的动态类型系统与其它数据库引擎的常用静态类型系统是向后兼容的,在这个意义上,工作在静态类型数据库上的 SQL 语句应该以同样的方式工作在 SQLite 中.然而,SQLite 中的动态类型允许

  • 简单分析SQLite4的一些设计改变

    1.0 内容提要 SQLite4 是一个放在库中的紧凑的,自包含的,零维护的的ACID数据库引擎, 像SQLite3一样, 但具有改进的接口和文件格式. 运行时环境封装到了一个对象之中. 使用了一个很不错的键值对存储引擎: 一个独立的大型键空间 - 不是SQLite3中那种每个表单独的键空间和索引. 按字典顺序的键排序. 多个存储引擎,可在运行时互换. 默认在磁盘上的存储殷勤使用了一个日志结构的合并数据库. 表的PRIMARY KEY真正被用作存储引擎的键. 可以使用小数点运算. 外键约束和递归

  • python装饰器三种装饰模式的简单分析

    学设计模式中有个装饰模式,用java实现起来不是很难,但是远远没有python简单,难怪越来越火了! 这里就简单讨论下python的几种装饰模式: 一 无参装饰器: # 装饰器 import time # 装饰器,记录函数运行时间 def decorator01(fun): def wapper(): stime = time.time() fun() etime = time.time() print("fun run time is {TIME}".format(TIME=etim

  • 分析Spring框架之设计与实现资源加载器

    目录 一.前言 二.目标 三.设计 四.实现 4.1.工程结构 4.2.资源加载接口定义和实现 4.3.包装资源加载器 4.4.Bean定义读取接口 4.5.Bean定义抽象类实现 4.6.解析XML处理Bean注册 五.测试 5.1.事先准备 5.2.配置文件 5.3.单元测试(资源加载) 5.4.单元测试(配置文件注册Bean) 六.总结 一.前言 你写的代码,能接的住产品加需求吗? 接,是能接的,接几次也行,哪怕就一个类一片的 if...else 也可以!但接完成什么样可就不一定了,会不会

  • java几种排序算法的实现及简单分析

    本文实例讲述了java几种排序算法的实现及简单分析.分享给大家供大家参考.具体如下: package test; public class first { /*普通的插入排序*/ public void insertSort(int[] list) { int i, j; list[0] = -999; //相当于设置一个监视哨兵,不用判断是否越界, //但要求数组从第二个数开始即i=1开始存储 for (i = 1; i < list.length; i++) { j = i; while (

  • 流氓软件ErrorSafe的简单分析清除方法与其他

    这里就简单描述ErrorSafe的分析和应对办法,目前,我这里只能找到两个版本,一个是1.0.22.4,另外一个是1.2.120.1,后者经升级应该是最新版本了,颠倒一下,先给出结论,并列举防范措施,最后是简单分析 结论和推广方式 1.从版本上来看,老版本的ErrorSafe还添加了服务等,而最新版本则是很简单的只添加自启动项,新版本更容易被清除 2.从程序上来看,该软件之所以被国际称为恶意软件,主要是指它的流氓推广方式及其恶劣,犯了众怒,才被人人喊打 由于该程序本身并无流氓特征,其流氓性主要体

  • linux下system函数的简单分析

    简单分析了linux下system函数的相关内容,具体内容如下 int __libc_system (const char *line) { if (line == NULL) /* Check that we have a command processor available. It might not be available after a chroot(), for example. */ return do_system ("exit 0") == 0; return do

  • Python数据可视化正态分布简单分析及实现代码

    Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandistribution),最早由A.棣莫弗在求二项分布的渐近公式中得到.C.F.高斯在研究测量误差时从另一个角度导出了它.P.S.拉普拉斯和高斯研究了它的性质.是一个在数学.物理及工程等领域都非常重要的概率分布,在统计学的许多方面有着重大的影响力. 正态曲线呈钟型,两头低,中间高,左右对称因其曲线呈钟形,因此人

  • 对python中的xlsxwriter库简单分析

    一.xlsxwriter 基本用法,创建 xlsx 文件并添加数据 官方文档:http://xlsxwriter.readthedocs.org/ xlsxwriter 可以操作 xls 格式文件 注意:xlsxwriter 只能创建新文件,不可以修改原有文件.如果创建新文件时与原有文件同名,则会覆盖原有文件 Linux 下安装: sudo pip install XlsxWriter Windows 下安装: pip install XlsxWriter # coding=utf-8 from

  • 简单分析React中的EffectList

    React中,会遍历EffectList来执行节点操作.生命周期方法.Effect方法,可以把EffectList比作圣诞树上挂的彩灯,而这颗圣诞树就是Fiber树. 为什么会存在EffectList呢?打个比方来说,一颗Fiber树中有一些Fiber节点需要执行componentDidMount方法,如果在Fiber树构建完成后,再遍历一次Fiber树,找到需要执行componentDidMount方法的Fiber节点,这是非常低效的. 而EffectList就解决了这个问题,在Fiber树构

  • 简单分析Java的求值策略原理

    形参和实参 java在定义方法时可以设置参数,参数分为形参和实参,形参是指在定义函数时用于接收外部传入数据的参数,而实参是指在调用方法时主调函数向被调函数传递的数据参数. 例如: public class Main { public static void main(String[] args) { int a = 2; int b = 3; System.out.println(sum(a,b));//5 } private static int sum(int i1,int i2){ ret

随机推荐