Small. Fast. Reliable.
Choose any three.

编者注: 本文档写于2004年,作为向从SQLite2过渡到SQLite3的程序员的指南。它被保留为SQLite历史记录的一部分。现代程序员应该参考SQLite的最新文档,该文档可以在本网站的其他地方找到。

SQLite版本3概述

SQLite 3.0版对该库进行了重要更改,包括:

本文档是针对已经熟悉SQLite 2.8版的用户的SQLite 3.0更改的快速介绍。

命名变更

在可预见的将来,将继续通过错误修复来支持SQLite 2.8版。为了使SQLite 2.8版和SQLite 3.0版和平共处,SQLite 3.0版中的密钥文件和API的名称已更改为包含字符“ 3”。例如,C程序使用的包含文件已从“ sqlite.h”更改为“ sqlite3.h”。并且用于与数据库进行交互的Shell程序的名称已从“ sqlite.exe”更改为“ sqlite3.exe”。通过这些更改,可以同时在同一系统上安装SQLite 2.8和SQLite 3.0。同样的C程序可以同时链接到SQLite 2.8和SQLite 3.0,并同时使用两个库。

新文件格式

SQLite数据库文件使用的格式已完全修改。旧版本2.1格式和新3.0格式彼此不兼容。SQLite 2.8版不会读取3.0版数据库文件,SQLite 3.0版不会读取2.8版数据库文件。

要将SQLite 2.8数据库转换为SQLite 3.0数据库,请准备好版本2.8和3.0的命令行外壳程序。然后输入如下命令:

sqlite OLD.DB .dump | sqlite3 NEW.DB

新的数据库文件格式为表使用B +树。在B +树中,所有数据都存储在树的叶子中,而不是存储在叶子和中间分支节点中。对表使用B +树可实现更好的可伸缩性和更大的数据字段的存储,而无需使用溢出页。传统的B树仍用于索引。

新的文件格式还支持512到65536字节之间的可变页面大小。页面的大小存储在文件头中,因此从理论上讲,尽管实际上尚未实现此功能,但同一库可以读取具有不同页面大小的数据库。

新文件格式从其磁盘映像中删除了未使用的字段。例如,索引仅使用B树记录的关键部分,而不使用数据。因此,对于索引,将省略记录数据长度的字段。整数值(例如密钥和数据的长度)使用可变长度编码存储,因此只需要一个或两个字节即可存储最常见的情况,但是如果需要,最多可以编码64位信息。整数和浮点数据以二进制形式存储在磁盘上,而不是像SQLite 2.8版那样转换为ASCII。这些更改共同导致数据库文件通常比SQLite 2.8版中的等效文件小25%至35%。

可在btreeInt.h 源文件的标题注释中和文件格式文档中找到SQLite 3.0版中使用的低级B树格式的详细信息 。

清单输入和BLOB支持

SQLite 2.8版将在内部处理各种格式的数据,但是当写入磁盘或通过其API进行交互时,SQLite 2.8始终将数据转换为ASCII文本。相反,SQLite 3.0将其内部数据表示形式展示给用户,并在适当的时候将二进制表示形式存储到磁盘中。为了支持BLOB,添加了非ASCII表示形式的公开。

SQLite 2.8版具有以下功能:无论表的声明类型如何,任何类型的数据都可以存储在任何表列中。此功能保留在3.0版中,但形式略有修改。每个表列将存储任何类型的数据,尽管列与其声明的数据类型所定义的数据格式具有相似性。当数据插入到列中时,该列将尝试将数据格式转换为该列的声明类型。所有SQL数据库引擎都可以执行此操作。区别在于,即使无法进行格式转换,SQLite 3.0仍将存储数据。

例如,如果您有一个表列声明为“ INTEGER”类型,并尝试插入字符串,则该列将查看文本字符串并查看其是否看起来像数字。如果字符串看起来确实像数字,则将其转换为数字,如果数字不包含小数部分,则将其转换为整数,然后以这种方式存储。但是,如果字符串不是格式正确的数字,则仍将其存储为字符串。类型为“ TEXT”的列尝试在存储数字之前将数字转换为ASCII文本表示形式。但是BLOB作为BLOB存储在TEXT列中,因为通常不能将BLOB转换为文本。

在大多数其他SQL数据库引擎中,数据类型与保存数据的表列相关联-与数据容器相关联。在SQLite 3.0中,数据类型与数据本身(而不是其容器)相关联。 保罗·格雷厄姆Paul Graham)在他的《ANSI Common Lisp 》一书中 将该属性称为“清单输入”。其他作者对“清单类型”一词有其他定义,因此请避免混淆。但是不管怎么说,这就是SQLite 3.0支持的数据类型模型。

有关SQLite 3.0版中数据类型的其他信息可 单独获得

支持UTF-8和UTF-16

SQLite 3.0的新API包含例程,该例程以主机的本机字节顺序将文本作为UTF-8和UTF-16接受。每个数据库文件将文本管理为UTF-8,UTF-16BE(大端)或UTF-16LE(小端)。在内部和磁盘文件中,到处都使用相同的文本表示形式。如果数据库文件指定的文本表示形式(在文件头中)与接口例程所需的文本表示形式不匹配,则文本将被即时转换。不断地将文本从一种表示形式转换为另一种表示形式在计算上可能会非常昂贵,因此建议程序员选择一种表示形式,并在整个应用程序中坚持使用。

在SQLite的当前实现中,SQL解析器仅适用于UTF-8文本。因此,如果您提供UTF-16文本,它将被转换。这只是一个实现问题,没有什么可以阻止SQLite的未来版本本地解析UTF-16编码的SQL的。

在创建新的用户定义的SQL函数和整理序列时,每个函数或整理序列都可以指定它是否适用于UTF-8,UTF-16be或UTF-16le。可以为每种编码注册单独的实现。如果需要SQL函数或整理序列,但当前文本编码的版本不可用,则将自动转换文本。和以前一样,这种转换需要花费大量的计算时间,因此建议程序员选择一种编码并坚持使用,以最大程度地减少不必要的格式调整。

SQLite对接收的文本并不特别关注,并且非常乐意处理未规范化甚至格式正确的UTF-8或UTF-16的文本字符串。因此,想要存储ISO8859数据的程序员可以使用UTF-8接口进行存储。只要不尝试使用UTF-16整理序列或SQL函数,就不会以任何方式修改文本的字节序列。

用户定义的整理序列

整理顺序只是文本的已定义顺序。当SQLite 3.0排序(或使用比较运算符,例如“ <”或“> =”)时,排序顺序首先由数据类型确定。

整理序列用于比较两个文本字符串。整理顺序不会更改NULL,数字或BLOB(仅文本)的顺序。

整理序列的功能是将两个要比较的字符串作为输入,如果第一个字符串小于,等于或大于第二个字符串,则返回负,零或正。SQLite 3.0带有一个名为“ BINARY”的内置内置整理序列,该序列使用标准C库中的memcmp()例程实现。BINARY整理序列适用于英文文本。对于其他语言或语言环境,可能希望使用其他整理顺序。

使用哪种整理顺序的决定由SQL中的COLLATE子句控制。COLLATE子句可以出现在表定义上,以定义表列或索引字段的默认整理顺序,或在SELECT语句的ORDER BY子句中。计划对SQLite进行的增强将包括标准CAST()语法,以允许定义表达式的整理顺序。

64位ROWID

表格的每一行都有唯一的rowid。如果表定义的列的类型为“ INTEGER PRIMARY KEY”,则该列将成为rowid的别名。但是,无论是否有INTEGER PRIMARY KEY列,每一行仍然具有一个rowid。

在SQLite 3.0版中,rowid是一个64位带符号整数。这是SQLite 2.8版的扩展,该版本仅允许32位的rowid。

为了最大程度地减少存储空间,将64位rowid存储为可变长度整数。0至127之间的Rowid仅使用一个字节。0到16383之间的Rowid仅使用2个字节。最多2097152使用三个字节。依此类推。允许使用负的rowid,但它们始终使用九个字节的存储空间,因此不鼓励使用它们。当SQLite自动生成rowid时,它们将始终为非负数。

改善并发性

SQLite 2.8版允许同时使用多个读取器或一个写入器,但不能同时使用。SQLite 3.0版允许一个进程开始写入数据库,而其他进程继续读取。编写器仍必须在短暂的时间间隔内获得数据库上的排他锁,以提交其更改,但是整个写入操作不再需要排他锁。一个更详细的报告上的SQLite的3.0版本的锁定行为是单独提供的。

现在,SQLite中还提供了有限形式的表级锁定。如果每个表都存储在单独的数据库文件中,则可以将这些单独的文件附加到主数据库(使用ATTACH命令),并且合并的数据库将作为一个数据库起作用。但是,仅根据需要在单个文件上获取锁。因此,如果将“数据库”重新定义为两个或多个数据库文件,则两个进程同时写入同一数据库是完全有可能的。为了进一步支持此功能,现在涉及两个或多个ATTACHed数据库的事务的提交是原子的。

学分

AOL开发人员支持并拥抱了出色的开源软件,部分原因使得SQLite 3.0版成为可能。