非常教程

Sqlite参考手册

其他 | Miscellaneous

35% Faster Than The Filesystem

1.总结

1.1. 注意事项

1.2. 相关研究

2.如何进行这些测量

2.1. 阅读性能测量

2.2. 写性能测量

2.3. 变化

3.一般调查结果

4.其他注意事项

4.1. 在Android上编译和测试

SQLite使用fread()或fwrite()读取和写入小块(例如缩略图)比使用fread()或fwrite()从磁盘上的单个文件读取或写入相同的块的速度快35%。

此外,保存10千字节blob的单个SQLite数据库使用的磁盘空间比单个文件中存储blob少20%。

性能上的差异出现了(我们相信),因为从SQLite数据库进行工作时,open()和close()系统调用只会被调用一次,而在使用blob中存储的blob时,会为每个blob调用open()和close单个文件。看起来调用open()和close()的开销大于使用数据库的开销。大小的减少是由于单个文件被填充到文件系统块大小的下一个倍数,而blob被更紧密地打包到SQLite数据库中。

本文中的测量是在2017-06-05的一周内使用3.19.2和3.20.0之间的SQLite版本进行的。您可能期望SQLite的未来版本能够更好地执行。

1.1. 注意事项

¹35%以上的数字是近似值。实际时间因硬件,操作系统和实验细节以及实际硬件上的随机性能波动而异。有关更多详细信息,请参阅下文。亲自尝试实验。向邮件列表报告重大偏差。

这35%的数据是基于作者轻松掌握的每台机器上的运行测试。本文的一些评论者报告说SQLite比他们的系统上的直接I / O具有更高的延迟。我们还不了解其中的差异。我们还看到有迹象显示,当使用冷文件系统缓存运行实验时,SQLite的性能不如直接I / O。

因此,让您的收获如此:SQLite的读取/写入延迟与磁盘上单个文件的读取/写入延迟相当具有竞争力。通常SQLite更快。有时SQLite几乎一样快。无论采用哪种方法,本文都反驳了常见的假设,即关系数据库必须比直接文件系统I / O慢。

1.2. 相关研究

Jim Gray和其他人研究了BLOB与Microsoft SQL Server的文件I / O的读取性能,发现从数据库中读取BLOB的速度要快于BLOB大小小于250KiB和1MiB。(纸)。在该研究中,即使内容保存在单独的文件中,数据库仍会保存内容的文件名。因此,即使只提取文件名,也会为每个BLOB查询数据库。在本文中,BLOB的关键是文件名,因此不需要初步的数据库访问。由于本文从阅读单个文件中读取内容时从不使用数据库,因此直接文件I / O变得更快的阈值小于Gray的论文中的阈值。

本网站的内部和外部BLOB文章是早期调查(大约2011年),它使用与Jim Gray论文相同的方法 - 将blob文件名存储为数据库中的条目 - 但是用于SQLite而不是SQL Server。

使用SQLite源代码树中的kvtest.c程序测量I / O性能。为了编译这个测试程序,首先将kvtest.c源文件收集到SQLite合并源文件“sqlite3.c”和“sqlite3.h”的目录中。然后在unix上运行如下命令:

gcc -Os -I. -DSQLITE_DIRECT_OVERFLOW_READ \
  kvtest.c sqlite3.c -o kvtest -ldl -lpthread

Or on Windows with MSVC:

cl -I. -DSQLITE_DIRECT_OVERFLOW_READ kvtest.c sqlite3.c

下面显示了针对Android编译的说明。

使用生成的“kvtest”程序,使用如下命令生成一个包含100,000个随机不可压缩blob的测试数据库,每个随机大小介于8,000和12,000字节之间:

./kvtest init test1.db --count 100k --size 10k --variance 2k

如果需要,您可以通过运行以下命令来验证新数据库:

./kvtest stat test1.db

接下来,使用如下命令将所有blob复制到目录中的单个文件中:

./kvtest export test1.db test1.dir

此时,您可以测量test1.db数据库使用的磁盘空间量以及test1.dir目录及其所有内容使用的空间量。在标准的Ubuntu Linux桌面上,数据库文件大小为1,024,512,000字节,test1.dir目录将使用1,228,800,000字节的空间(根据“du -k”),大约比数据库多20%。

上面创建的“test1.dir”目录将所有blob放入一个文件夹中。据推测,当一个目录包含100,000个对象时,某些操作系统的性能会很差。为了测试这个,kvtest程序还可以将Blob存储在文件夹层次结构中,每个文件夹的文件和/或子目录不超过100个。可以使用“export”命令的--tree命令行选项来创建Blob的备选磁盘表示形式,如下所示:

./kvtest export test1.db test1.tree --tree

test1.dir目录将包含名称为“000000”,“000001”,“000002”等的100,000个文件,但test1.tree目录将包含子目录中的相同文件,如“00/00/00”,“00 / 00/01“等。test1.dir和test1.test目录占用大约相同的空间量,但由于额外的目录条目,test1.test略微大一些。

以下所有实验都与“test1.dir”或“test1.tree”相同。在任何情况下,无论操作系统如何,性能差异都很小。

使用以下命令测量从数据库和单个文件中读取blob的性能:

./kvtest run test1.db --count 100k --blob-api
./kvtest run test1.dir --count 100k --blob-api
./kvtest run test1.tree --count 100k --blob-api

根据您的硬件和操作系统,您应该看到test1.db数据库文件的读取速度比从test1.dir或test1.tree文件夹中的单个文件读取速度快大约35%。由于缓存的不同,结果可能因运行而异,因此建议您多次运行测试,并根据您的要求采取平均或最差情况或最佳情况。

数据库读取测试的--blob-api选项会导致kvtest使用SQLite的sqlite3_blob_read()功能加载blob的内容,而不是运行纯SQL语句。这有助于SQLite在读取测试时运行得更快一些。您可以省略该选项来比较SQLite运行SQL语句的性能。在这种情况下,SQLite仍然会执行直接读取,但不如使用sqlite3_blob_read()时那么多。对于从单个磁盘文件读取的测试,将忽略--blob-api选项。

通过添加--update选项来衡量写入性能。这会导致斑点被另一个大小完全相同的随机斑点覆盖。

./kvtest run test1.db --count 100k --update
./kvtest run test1.dir --count 100k --update
./kvtest run test1.tree --count 100k --update

上面的写作测试并不完全公平,因为SQLite正在进行电源安全交易,而直接写入磁盘的交易则不是。为了使测试更加平等,在SQLite中添加--nosync选项来禁止调用fsync()或FlushFileBuffers()来强制内容到磁盘,或者使用--fsync选项来实现直接到达磁盘测试强制他们在更新磁盘文件时调用fsync()或FlushFileBuffers()。

默认情况下,kvtest在单个事务中运行数据库I / O测量。使用--multitrans选项在单独的事务中运行每个blob读取或写入。--multitrans选项使得SQLite变得更慢,并且与直接磁盘I / O无竞争力。这个选项再次证明,为了从SQLite中获得最高的性能,您应该在单个事务中尽可能多地分组数据库交互。

还有很多其他的测试选项,可以通过运行命令来查看:

./kvtest help

2.1。阅读性能测量

下面的图表显示了在五个不同系统上使用kvtest.c收集的数据:

  • Win7:大约2009年戴尔Inspiron笔记本电脑,奔腾双核2.30GHz,4GiB内存,Windows7。
  • Win10:2016年联想YOGA 910,2.70GHz的Intel i7-7500,16GiB RAM,Windows10。
  • Mac:2015 MacBook Pro,3.1GHz Intel Core i7,16GiB RAM,MacOS 10.12.5
  • Ubuntu:使用Intel i7-4770K(3.50GHz,32GiB RAM,Ubuntu 16.04.2 LTS)构建的桌面
  • Android下载应用程序类别Galaxy S3,ARMv7,2GiB RAM

除Win7以外,所有机器都使用SSD,硬盘驱动器。测试数据库是大小均匀分布在8K和12K之间的100K blob,总共大约1 GB的内容。数据库页面大小为4KiB。所有这些测试都使用了-DSQLITE_DIRECT_OVERFLOW_READ编译时选项。测试运行多次。第一次运行是用来预热高速缓存,并放弃它的时间。

下面的图表显示了直接从文件系统读取blob的平均时间与从SQLite数据库读取同一个blob所需的时间。实际的时间因系统而异(Ubuntu桌面比Galaxy S3手机要快得多)。此图表显示了从文件中读取Blob所需的时间除以来自数据库所需时间的比率。图表中最左边的列是从数据库读取的标准化时间,以供参考。

在该图表中,一次准备了SQL语句(“SELECT v FROM kv WHERE k =?1”)。然后,对于每个blob,blob键值都绑定到?1参数,并对语句进行评估以提取blob内容。

该图表显示,在Windows10上,可以从SQLite数据库读取的内容比从磁盘直接读取快5倍。在Android上,SQLite仅比从磁盘读取快35%。

35% Faster Than The Filesystem

图1:相对于直接文件系统读取的SQLite读取延迟。

100K blob,平均每个10KB,使用SQL的随机顺序

通过绕过SQL层并直接使用sqlite3_blob_read()接口读取blob内容,可以稍微改进性能,如下图所示:

35% Faster Than The Filesystem

图2:相对于直接文件系统读取的SQLite读取延迟。

100K blob,平均大小10KB,随机顺序

using sqlite3_blob_read().

通过使用SQLite的内存映射I / O功能可以进一步提高性能。在下一个图表中,整个1GB数据库文件是内存映射的,使用sqlite3_blob_read()接口读取blob(以随机顺序)。通过这些优化,SQLite的速度是Android或MacOS-X的两倍,比Windows快10倍以上。

35% Faster Than The Filesystem

图3:与直接文件系统读取相关的SQLite读取延迟。

100K blob,平均大小10KB,随机顺序

using sqlite3_blob_read() from a memory-mapped database.

第三个图表显示,从SQLite中读取blob内容的速度是从Mac和Android的磁盘上的单个文件读取速度的两倍,而Windows的速度却快了十倍。

2.2. 写性能测量

写入较慢。在所有使用直接I / O和SQLite的系统上,写入性能比读取速度慢5到15倍。

写性能测量是通过用不同的blob替换(覆盖)整个blob来完成的。所有这些实验中的斑点都是随机的,不可压缩的。由于写入速度比读取速度慢得多,数据库中只有10,000个数据块被替换。要被替换的斑点是随机选择的,并没有特定的顺序。

直接到磁盘的写操作使用fopen()/ fwrite()/ fclose()来完成。默认情况下,在下面显示的所有结果中,OS文件系统缓冲区永远不会使用fsync()或FlushFileBuffers()刷新到持久存储。换句话说,没有试图使直接到磁盘写入交易或电力安全。我们发现,在写入的每个文件上调用fsync()或FlushFileBuffers()会导致直接到磁盘的存储速度比写入SQLite慢10倍或更多。

下一个图表比较了WAL模式下的SQLite数据库更新与磁盘上单独文件的原始直接到磁盘覆盖。PRAGMA同步设置为NORMAL。所有数据库写入都在单个事务中。数据库写入的计时器在事务提交后但在运行检查点之前停止。请注意,与直接到磁盘写入不同,SQLite写入是事务性和电源安全的,但由于同步设置是NORMAL而不是FULL,因此事务不会持久。

35% Faster Than The Filesystem

图4:与直接文件系统写入相关的SQLite写入延迟。

10K blob,平均大小10KB,随机顺序,

具有同步NORMAL的WAL模式,

不包括检查点时间

写入实验的android性能数字被忽略,因为Galaxy S3上的性能测试非常随机。完全相同的实验连续两次运行会产生截然不同的时间。而且,公平地说,android上的SQLite性能比直接写入磁盘要慢一些。

下图显示了在禁用事务时(PRAGMA journal_mode = OFF)和PRAGMA同步设置为OFF时SQLite与直接到磁盘的性能比较。这些设置使SQLite与直接到磁盘的写入处于同等地位,这就是说,由于系统崩溃和电源故障,它们使数据容易受损。

35% Faster Than The Filesystem

图5:与直接文件系统写入相关的SQLite写入延迟。

10K blob,平均大小10KB,随机顺序,

日志禁用,同步OFF。

在所有写入测试中,在运行直接磁盘性能测试之前禁用防病毒软件非常重要。我们发现反病毒软件的直接到磁盘的速度减慢了一个数量级,而它对SQLite的写入影响很小。这可能是由于直接到磁盘更改了数千个单独的文件,这些文件都需要通过防病毒进行检查,而SQLite写入仅更改单个数据库文件。

2.3. 变化

编译时选项-DSQLITE_DIRECT_OVERFLOW_READ会导致SQLite在从溢出页面读取内容时绕过它的页面缓存。这有助于10K blob的数据库读取速度提高一点,但速度并不快。与没有SQLITE_DIRECT_OVERFLOW_READ编译时选项的直接文件系统读取相比,SQLite仍然具有速度优势。

其他编译时选项(如使用-O3代替-Os或使用-DSQLITE_THREADSAFE = 0和/或其他一些推荐的编译时选项)可能有助于SQLite相对于直接文件系统读取运行得更快。

测试数据中斑点的大小会影响性能。对于较大的blob,文件系统通常会更快,因为open()和close()的开销会分摊到I / O的更多字节上,而数据库在平均blob大小下降时速度和空间都会更高效。

  1. 与读取和写入时相比,SQLite与存储在磁盘上单独文件中的斑点相比具有竞争性,并且通常更快。
  1. 在启用防病毒保护功能时,SQLite比在Windows上直接写入磁盘要快得多。由于防病毒软件在Windows中默认情况下处于打开状态,这意味着SQLite通常比Windows上的直接磁盘写入快得多。
  1. 对于所有系统以及SQLite和直接到磁盘的I / O,读取速度比写入速度快一个数量级。
  1. I / O性能在很大程度上取决于操作系统和硬件。在得出结论之前进行自己的测量。
  1. 其他一些SQL数据库引擎建议开发人员将blob存储在单独的文件中,然后将文件名存储在数据库中。在这种情况下,在打开和读取文件之前必须首先查阅数据库以查找文件名,只需将整个blob存储在数据库中,就可以使用SQLite更快地读写数据。有关更多信息,请参阅内部对外部BLOB文章。

4.1。在Android上编译和测试

kvtest程序在Android上进行编译和运行,如下所示。首先安装Android SDK和NDK。然后准备一个名为“android-gcc”的脚本,大致如下所示:

#!/bin/sh
#
NDK=/home/drh/Android/Sdk/ndk-bundle
SYSROOT=$NDK/platforms/android-16/arch-arm
ABIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin
GCC=$ABIN/arm-linux-androideabi-gcc
$GCC --sysroot=$SYSROOT -fPIC -pie $*

使该脚本可执行并将其放在$ PATH中。然后编译kvtest程序如下:

android-gcc -Os -I. kvtest.c sqlite3.c -o kvtest-android

接下来,将生成的kvtest-android可执行文件移动到Android设备上:

adb push kvtest-android /data/local/tmp

最后使用“adb shell”在Android设备上获取shell提示符,cd到/ data / local / tmp目录中,并像其他任何unix主机一样开始运行测试。

 SQLite在公共领域。

其他 | Miscellaneous相关

1.8+3 Filenames
2.An Asynchronous I/O Module For SQLite
3.Appropriate Uses For SQLite
4.Architecture of SQLite
5.Atomic Commit In SQLite
6.Automatic Undo/Redo With SQLite
7.Benefits of SQLite As A File Format
8.Change in Default Page Size in SQLite Version 3.12.0
9.Clustered Indexes and the WITHOUT ROWID Optimization
10.Compile-time Options
11.Constraint Conflict Resolution in SQLite
12.Custom Builds Of SQLite
13.Deterministic SQL Functions
14.Distinctive Features Of SQLite
15.EXPLAIN QUERY PLAN
16.Features Of SQLite
17.File Format Changes in SQLite
18.Full-Featured SQL
19.High Reliability
20.Hints for Debugging SQLite
21.How SQLite Is Tested
22.How To Compile SQLite
23.How To Download Canonical SQLite Source Code
24.Imposter Tables
25.In-Memory Databases
26.Indexes On Expressions
27.Internal Versus External BLOBs
28.Isolation In SQLite
29.Long Term Support
30.Maintaining Private Branches Of SQLite
31.Many Small Queries Are Efficient In SQLite
32.Measuring and Reducing CPU Usage in SQLite
33.Memory-Mapped I/O
34.NULL Handling in SQLite
35.Partial Indexes
36.Pointer Passing Interfaces
37.Powersafe Overwrite
38.Release History Of SQLite
39.Result and Error Codes
40.Row Values
41.Rowid Tables
42.Run-Time Loadable Extensions
43.SQL Features That SQLite Does Not Implement
44.sqldiff.exe: Database Difference Utility
45.SQLite As An Application File Format
46.SQLite Autoincrement
47.SQLite Backup API
48.SQLite Changes From Version 3.4.2 To 3.5.0
49.SQLite Changes From Version 3.5.9 To 3.6.0
50.SQLite Database Speed Comparison
51.SQLite File IO Specification
52.SQLite Frequently Asked Questions
53.SQLite In 5 Minutes Or Less
54.SQLite is a Self Contained System
55.SQLite Is Serverless
56.SQLite Is Transactional
57.SQLite Library Footprint
58.SQLite Shared-Cache Mode
59.SQLite Unlock-Notify API
60.SQLite Version 3 Overview
61.SQLite: Single File Database
62.Temporary Files Used By SQLite
63.TH3
64.The COMPLETION() Table-Valued Function
65.The CSV Virtual Table
66.The dbhash.exe Utility Program
67.The DBSTAT Virtual Table
68.The Error And Warning Log
69.The generate_series Table-Valued Function
70.The OS Backend (VFS) To SQLite
71.The Spellfix1 Virtual Table
72.The SQLite Amalgamation
73.The SQLite Bytecode Engine
74.The sqlite3_analyzer.exe Utility Program
75.The SQLITE_STMT Virtual Table
76.The UNION Virtual Table
77.The Virtual Database Engine of SQLite
78.Uniform Resource Identifiers
79.Using SQLite In Multi-Threaded Applications
80.Version Numbers in SQLite
81.What If OpenDocument Used SQLite?
82.Why Is SQLite Coded In C
83.Zero-Configuration
Sqlite

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来

主页 https://sqlite.org/
源码 https://www.sqlite.org/src/
发布版本 3.21.0

Sqlite目录

1.C界面 | C Interface
2.C Interface: Session Module
3.CLI
4.数据库文件表 | Database File Format
5.数据类 | Datatypes
6.动态内存分配 | Dynamic Memory Allocation
7.外键约束 | Foreign Key Constraints
8.全文索引 | Full-Text Search
9.损坏方式 | How To Corrupt
10.JSON
11.语言 | Language
12.局限性 | Limits
13.锁定和并发 | Locking and Concurrency
14.其他 | Miscellaneous
15.PRAGMA Statements
16.查询计划程序 | Query Planner
17.R*Tree Module
18.RBU Extension
19.语法图 | Syntax Diagrams
20.Tcl Interface
21.虚拟表机制 | Virtual Table Mechanism
22.预写日志 | Write-Ahead Logging
23.SQL 教程
24.SQL 简介
25.SQL 语法
26.SQL DELETE 语句
27.SQL UPDATE 语句
28.SQL NOT NULL 约束
29.SQL 约束
30.SQL CREATE TABLE 语句
31.SQL CREATE DATABASE 语句
32.SQL INSERT INTO SELECT 语句
33.SQL SELECT INTO 语句
34.SQL CREATE VIEW、REPLACE VIEW、 DROP VIEW 语句
35.SQL AUTO INCREMENT 字段
36.SQL ALTER TABLE 语句
37.SQL 撤销索引、表以及数据库
38.SQL CREATE INDEX 语句
39.SQL DEFAULT 约束
40.SQL CHECK 约束
41.SQL FOREIGN KEY 约束
42.SQL PRIMARY KEY 约束
43.SQL UNIQUE 约束
44.SQL 通用数据类型
45.SQL ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数
46.SQL NULL 值 – IS NULL 和 IS NOT NULL
47.SQL Server 和 MySQL 中的 Date 函数
48.SQL MS Access、MySQL 和 SQL Server 数据类型
49.SQL 函数
50.SQL 总结
51.SQL 主机
52.SQL 快速参考
53.SQL ROUND() 函数
54.SQL Server GETDATE() 函数
55.MySQL DATE_FORMAT() 函数
56.MySQL DATEDIFF() 函数
57.MySQL DATE_SUB() 函数
58.MySQL DATE_ADD() 函数
59.MySQL EXTRACT() 函数
60.MySQL DATE() 函数
61.MySQL CURTIME() 函数
62.MySQL CURDATE() 函数
63.MySQL NOW() 函数
64.SQL Server CONVERT() 函数
65.SQL Server DATEDIFF() 函数
66.SQL Server DATEADD() 函数
67.SQL Server DATEPART() 函数
68.SQLite 命令
69.SQLite 安装
70.SQLite 简介
71.SQLite 运算符
72.SQLite Select 语句
73.SQLite 删除表
74.SQLite 创建表
75.SQLite Insert 语句
76.SQLite 分离数据库
77.SQLite 附加数据库
78.SQLite 创建数据库
79.SQLite 数据类型
80.SQLite 语法
81.SQLite Order By
82.SQLite Limit 子句
83.SQLite Glob 子句
84.SQLite Like 子句
85.SQLite Delete 语句
86.SQLite Update 语句
87.SQLite AND/OR 运算符
88.SQLite Where 子句
89.SQLite 表达式
90.SQLite Distinct 关键字
91.SQLite Having 子句
92.SQLite Group By
93.SQLite Join
94.SQLite 约束
95.SQLite PRAGMA
96.SQLite 事务
97.SQLite 视图
98.SQLite Truncate Table
99.SQLite Alter 命令
100.SQLite Indexed By