Temporary Files Used By SQLite
1.介绍
2.九种临时文件
2.1.回滚日志
2.2.预写日志(WAL)文件
2.3.共享内存文件
2.4.主日志文件
2.5.语句日记文件
2.6.TEMP数据库
2.7.视图和子查询的实现
2.8.瞬态指数
2.9.瞬时数据库由VACUUM使用
3. SQLITE_TEMP_STORE编译时间参数和Pragma
4.其他临时文件优化
5.临时文件存储位置
1.介绍
SQLite的一个独特功能是数据库由单个磁盘文件组成。这简化了SQLite的使用,因为移动或备份数据库就像复制单个文件一样简单。它也使得SQLite适合用作应用程序文件格式。但是,当一个完整的数据库保存在单个磁盘文件中时,SQLite在处理数据库的过程中会使用许多临时文件。
本文介绍SQLite创建和使用的各种临时文件。它描述了何时创建文件,何时删除文件,如何使用它们,为什么它们很重要,以及如何避免在创建临时文件昂贵的系统中使用这些文件。
SQLite使用临时文件的方式不被视为SQLite与应用程序之间的合同的一部分。本文档中的信息是SQLite在编写或上次更新本文档时如何运行的正确说明。但是,不能保证未来版本的SQLite将以相同的方式使用临时文件。新版本的临时文件可能会被采用,并且一些当前的临时文件用途可能会在以后的SQLite版本中停用。
2.九种临时文件
SQLite目前使用九种不同类型的临时文件:
- 回滚日志
- 硕士期刊
- 预写日志(WAL)文件
- 共享内存文件
- 陈述期刊
- TEMP数据库
- 视图和子查询的实现
- 瞬态指数
- VACUUM使用的瞬态数据库
关于每个这些临时文件类型的附加信息在续集中。
2.1.回滚日志
回滚日志是用于在SQLite中实现原子提交和回滚功能的临时文件。(有关这种工作方式的详细讨论,请参阅单独的文档,标题为SQLite中的Atomic Commit。)回滚日志始终与数据库文件位于同一目录中,并且与数据库文件具有相同的名称,除了8个字符“ -日志 “回滚日志通常在事务首次启动时创建,通常在事务提交或回退时删除回滚日志文件对于实现SQLite的原子提交和回滚功能非常重要没有回滚日志SQLite将无法回滚未完成的事务,并且如果在事务中间发生崩溃或断电,整个数据库可能会在没有回滚日志的情况下损坏。
回滚日志 通常 分别在事务的开始和结束时创建和销毁。但是这个规则也有例外。
如果事务中间发生崩溃或断电,则回滚日志文件保留在磁盘上。下一次另一个应用程序尝试打开数据库文件时,它会注意到存在已弃用的回滚日志(在这种情况下我们称之为“热日志”),并使用日志中的信息将数据库恢复到其之前的状态未完成交易的开始。这是SQLite如何实现原子提交。
如果应用程序使用杂注将SQLite置于独占锁定模式:
PRAGMA locking_mode=EXCLUSIVE;
SQLite在排他锁定模式会话的第一个事务开始时创建一个新的回滚日志。但在交易结束时,它不会删除回滚日志。回滚日志可能会被截断,或者其标头可能被清零(取决于您使用的SQLite版本),但回滚日志不会被删除。退出独占访问模式之前,回滚日志不会被删除。
journal_mode附注也更改了回滚日记的创建和删除。默认日志模式是DELETE,这是在每个事务结束时删除回滚日志文件的默认行为,如上所述。PERSIST日志模式放弃删除日志文件,而是用零覆盖回退日志头,这样可以防止其他进程回滚日志,从而具有与删除日志文件相同的效果,但无需实际删除文件从磁盘。换句话说,日记模式PERSIST表现出与EXCLUSIVE锁定模式中所看到的相同的行为。OFF日志模式导致SQLite完全忽略回滚日志。换句话说,如果日志模式设置为OFF,则不会写回滚日志。OFF日志模式禁用SQLite的原子提交和回滚功能。设置OFF日志模式时,ROLLBACK命令不可用。如果在使用OFF日志模式的事务中发生崩溃或断电,则无法恢复,数据库文件可能会损坏。MEMORY日志模式会使回滚日志存储在内存中而不是磁盘上。当日志模式为MEMORY时,ROLLBACK命令仍然有效,但由于没有文件存在磁盘上进行恢复,所以在使用MEMORY日志模式的事务中间发生崩溃或断电可能会导致数据库损坏。如果在使用OFF日志模式的事务中发生崩溃或断电,则无法恢复,数据库文件可能会损坏。MEMORY日志模式会使回滚日志存储在内存中而不是磁盘上。当日志模式为MEMORY时,ROLLBACK命令仍然有效,但由于没有文件存在磁盘上进行恢复,所以在使用MEMORY日志模式的事务中间发生崩溃或断电可能会导致数据库损坏。如果在使用OFF日志模式的事务中发生崩溃或断电,则无法恢复,数据库文件可能会损坏。MEMORY日志模式会使回滚日志存储在内存中而不是磁盘上。当日志模式为MEMORY时,ROLLBACK命令仍然有效,但由于没有文件存在磁盘上进行恢复,所以在使用MEMORY日志模式的事务中间发生崩溃或断电可能会导致数据库损坏。
2.2.预写日志(WAL)文件
当SQLite在WAL模式下运行时,使用预写日志或WAL文件代替回滚日志。与回滚日志一样,WAL文件的目的是实现原子提交和回滚。WAL文件始终与数据库文件位于同一目录中,并且与数据库文件具有相同的名称,除了附加了4个字符“ -wal ”。WAL文件在与数据库的第一个连接打开时创建,通常在关闭数据库的最后一个连接时删除。但是,如果最后一次连接没有完全关闭,WAL文件将保留在文件系统中,并在下次打开数据库时自动清除。
2.3.共享内存文件
在WAL模式下运行时,与同一数据库文件关联的所有SQLite数据库连接需要共享一些用作WAL文件索引的内存。在大多数实现中,这个共享内存是通过在为此唯一目的创建的文件上调用mmap()来实现的:共享内存文件。共享内存文件(如果存在)位于与数据库文件相同的目录中,并且与数据库文件具有相同的名称,但附加了4个字符“ -shm ”。共享内存文件只有在WAL模式下运行时才存在。
共享内存文件不包含持久内容。共享内存文件的唯一目的是提供一个共享内存块,供多个进程在WAL模式下访问同一个数据库时使用。如果VFS能够提供访问共享内存的替代方法,则可以使用该替代方法而不是共享内存文件。例如,如果PRAGMA locking_mode设置为EXCLUSIVE(意味着只有一个进程能够访问数据库文件),那么共享内存将从堆中分配,而不是从共享内存文件中分配,共享内存文件将永远不会被创造。
共享内存文件具有与其关联的WAL文件相同的生命周期。共享内存文件在创建WAL文件时创建,当WAL文件被删除时删除。在WAL文件恢复期间,基于正在恢复的WAL文件的内容从头开始重新创建共享内存文件。
2.4.主日志文件
当单个事务对使用ATTACH语句添加到单个数据库连接的多个数据库进行更改时,主日志文件将用作原子提交过程的一部分。主日志文件始终与主数据库文件位于同一目录中(主数据库文件是在创建数据库连接的原始sqlite3_open(),sqlite3_open16()或sqlite3_open_v2()调用中标识的数据库)一个随机后缀。主日志文件包含在事务处理期间更改的所有附加辅助数据库的名称。当主日志文件被删除时,多数据库事务提交。有关更多详细信息,请参阅标题为“Atomic Commit In SQLite”的文档。
如果没有主日志,多数据库事务上的事务提交对每个数据库都是原子的,但在所有数据库中不会是原子的。换句话说,如果提交在中途因崩溃或断电而中断,则对其中一个数据库的更改可能会完成,而对另一个数据库的更改可能会回滚。主日志会导致所有数据库中的所有更改都回滚或一起提交。
主日志文件仅针对涉及多个数据库文件的COMMIT操作创建,其中至少有两个数据库满足以下所有要求:
- 数据库由事务修改
- PRAGMA同步设置不关闭
- PRAGMA journal_mode不是OFF,MEMORY或WAL
这意味着,当数据库文件关闭同步或使用OFF,MEMORY或WAL日志模式时,SQLite事务在断电时不会在多个数据库文件间原子化。对于同步OFF和对于journal_mode OFF和MEMORY,如果事务提交被断电中断,数据库通常会损坏。对于WAL模式,单个数据库文件在断电时自动更新,但在多文件事务中,某些文件可能会回滚,而其他文件在恢复供电后会前滚。
2.5.语句日记文件
语句日志文件用于在较大的事务中回滚单个语句的部分结果。例如,假设UPDATE语句将尝试修改数据库中的100行。但是,在修改前50行后,UPDATE会触发一个约束违规行为,该行为会阻止整个语句。语句日志用于撤消前50行更改,以便数据库恢复到语句开始时的状态。
语句日志仅针对UPDATE或INSERT语句创建,该语句可能会更改数据库的多行,并且可能触发触发器中的约束或RAISE异常,因此需要撤消部分结果。如果UPDATE或INSERT未包含在BEGIN ... COMMIT内,并且在同一数据库连接上没有其他活动语句,则不会创建语句日志,因为可以使用普通回滚日志。如果使用替代冲突解决算法,语句日志也会被忽略。例如: