sqlite之WAL模式
- 概述
在3.7.0以后,WAL(Write-Ahead Log)模式可以使用,是另一种实现事务原子性的方法。- WAL的优点
- 在大多数情况下更快
- 并行性更高。因为读操作和写操作可以并行。
- 文件IO更加有序化,串行化(more sequential)
- 使用fsync()的次数更少,在fsync()调用时好时坏的机器上较为未定。
- 缺点
- 一般情况下需要VFS支持共享内存模式。(shared-memory primitives)
- 操作数据库文件的进程必须在同一台主机上,不能用在网络操作系统。
- 持有多个数据库文件的数据库连接对于单个数据库时原子的,对于全部数据库是不原子的。
- 进入WAL模式以后不能修改page的size。
- 不能打开只读的WAL数据库(Read-Only Databases),这进程必须有"-shm"文件的写权限。
- 对于只进行读操作,很少进行写操作的数据库,要慢那么1到2个百分点。
- 会有多余的"-wal"和"-shm"文件
- 需要开发者注意checkpointing
- WAL的优点
原理
回滚日志的方法是把为改变的数据库文件内容写入日志里,然后把改变后的内容直接写到数据库文件中去。在系统crash或掉电的情况下,日志里的内容被重新写入数据库文件中。日志文件被删除,标志commit着一次commit的结束。
WAL模式于此此相反。原始为改变的数据库内容在数据库文件中,对数据库文件的修改被追加到单独的WAL文件中。当一条记录被追加到WAL文件后,标志着一次commit的结束。因此一次commit不必对数据库文件进行操作,当正在进行写操作时,可以同时进行读操作。多个事务的内容可以追加到一个WAL文件的末尾。
- checkpoint
最后WAL文件的内容必须更新到数据库文件中。把WAL文件的内容更新到数据库文件的过程叫做一次checkpoint。
回滚日志的方法有两种操作:读和写。WAL有三种操作,读、写和checkpoint。
默认的,SQL会在WAL文件达到1000page时进行一次checkpoint。进行WAL的时机也可以由应用程序自己决定。 - 并发性
当一个读操作发生在WAL模式的数据库上时,会首先找到WAL文件中最后一次提交,叫做"end mark"。每一个事务可以有自己的"end point",但对于一个给定额事务来说,end mark是固定的。
当读取数据库中的page时,SQLite会先从WAL文件中寻找有没有对应的page,从找出离end mark最近的那一条记录;如果找不到,那么就从数据库文件中寻找对一个的page。为了避免每次事务都要扫描一遍WAL文件,SQLite在共享内存中维护了一个"wal-index"的数据结构,帮助快速定位page。
写数据库只是把新内容加到WAL文件的末尾,和读操作没有关系。由于只有一个WAL文件,因此同时只能有一个写操作。
checkpoint操作可以和读操作并行。但是如果checkpoint把一个page写入数据库文件,而且这个page超过了当前读操作的end mark时,checkpoint必须停止。否则会把当前正在读的部分覆盖掉。下次checkpoint时,会从这个page开始往数据库中拷贝数据。
当写操作时,会检查WAL文件被拷贝到数据库的进度。如果已经完全被拷贝到数据库文件中,已经同步,并且没有读操作在使用WAL文件,那么会把WAL文件清空,从其实开始追加数据。保证WAL文件不会无限制增长。 - 性能
写操作是很快的,因为只需要进行一次写操作,并且是顺序的(不是随机的,每次都写到末尾)。而且,把数据刷到磁盘上是不必须的。(如果PRAGMA synchronous是FULL,每次commit要刷一次,否则不刷。)
读操作的性能有所下降,因为需要从WAL文件中查找内容,花费的时间和WAL文件的大小有关。wal-index可以缩短这个时间,但是也不能完全避免。因此需要保证WAL文件的不会太大。
为了保护数据库不被损坏,需要在把WAL文件写入数据库之前把WAL文件刷入磁盘;在重置WAL文件之前要把数据库内容刷入数据库文件。此外checkpoint需要查找操作。这些因素使得checkpoint比写操作慢一些。
默认策略是很多线程可以增长WAL文件。把WAL文件大小变得比1000page大的那个线程要负责进行checkpoint。会导致绝大部分读写操作都是很快的,随机有一个写操作非常慢。也可以禁用自动checkpoint的策略,定期在一个线程或进程中进行checkpoint操作。
高效的写操作希望WAL文件越大越好;高效的读操作希望WAL文件越小越好。两者存在一个tradeoff。
- checkpoint
激活和配置WAL模式
PRAGMA journal_mode=WAL;,如果成功,会返回"wal"。自动checkpoint
可以手动checkpointsqlite3_wal_checkpoint(sqlite3 *db, const char *zDb)
配置checkpoint
sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
Application-Initiated Checkpoints
可以在任意一个可以进行写操作的数据库连接中调用sqlite3_wal_checkpoint_v2()或sqlite3_wal_checkpoint()。WAL模式的持久性
当一个进程设置了WAL模式,关闭这个进程,重新打开这个数据库,仍然是WAL模式。
如果在一个数据库连接中设置了WAL模式,那么这个数据库的所有连接都将被设为WAL模式。
只读数据库
如果数据库需要恢复,而你只有读权限,没有写权限,那么你不能读取这个数据库,因为进行读操作的第一步就是恢复数据库。
类似的,因为WAL模式下的数据库进行读操作时,需要类似数据库恢复的操作,因此如果只有读权限,也不能对打开数据库。
WAL的实现需要有一个基于WAL文件的哈希表在共享内存中。在Unix和Windows的VFS实现中,是基于MMap的。将共享内存映射到同目录下的"-shm"文件中。因此即使是对WAL模式下的数据库文件进行读操作,也需要写权限。
为了把数据库文件转化为只读的文件,需要先把这个数据库的日志模式改为"delete".避免过大的WAL文件
WAL-index的共享内存实现
在WAL发布之前,曾经尝试过将wal-index映射到临时目录,如/dev/shm或/tmp。但是不同的用户看到的目录是不同的,所以此路不通。
后来尝试将wal-index映射到匿名的虚拟内存块中,但是无法在不用的Unix版本中保持一致。
最终决定采用将wal-index映射到同目录下。这样子会导致不必要的磁盘IO。但是问题不大,是因为wal-index很少超过32k,而且从不会调用sync操作。此外,最后一个数据库连接关闭以后,这个文件会被删除。
如果这个数据库只会被一个进程使用,那么可以使用heap memory而不是共享内存。不用共享内存实现WAL
在3.7.4版本以后,只要SQLite的lock mode被设为EXCLUSIVE,那么即使共享内存不支持,也可以使用WAL模式。
换句话说,如果只有一个进程使用SQLite,那么不用共享内存也可以使用WAL。
此时,将lock mode改为normal是无效的,需要实现取消WAL模式。
sqlite之WAL模式的更多相关文章
- GRDB使用SQLite的WAL模式
GRDB使用SQLite的WAL模式 WAL全称是Write Ahead Logging,它是SQLite中实现原子事务的一种机制.该模式是从SQLite 3.7.0版本引入的.再此之前,SQLi ...
- SQLite 的 CodeFirst 模式
目录 问题描述 解决方案 安装依赖包 修改程序配置 App.config 创建模型对象 Person.cs 创建数据上下文 PersonDbContext.cs 主程序调用 Program.cs 注意 ...
- SQLite的WAL机制
标注:本文部分有黏贴这里的资料,另外还加了一些自己的笔记 使用CoreData或者SQLite3的时候,我们创建的数据库, 在存储的文件夹中有三个文件:分别为:**.sqlite **.sqlite ...
- 【腾讯Bugly干货分享】微信iOS SQLite源码优化实践
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57b58022433221be01499480 作者:张三华 前言 随着微信iO ...
- SQLiteOpenHelper/SQLiteDatabase/Cursor源代码解析
转载请注明出处:http://blog.csdn.net/y_zhiwen/article/details/51583188 Github地址.欢迎star和follow 新增android sqli ...
- Sqlite学习笔记(三)&&WAL性能测试
WAL是SQLite3.7.0版本引入的一个重大改进.SQLite官网宣称在很多使用场景下,WAL模型的性能都要好于默认的DELETE模式.下面将针对几个主要场景对WAL性能做测试,测试的硬件与xxx ...
- 浅析SQLite的锁机制和WAL技术
锁机制 SQLite基于锁来实现并发控制.SQLite的锁是粗粒度的,并不拥有PostgreSQL那样细粒度的行锁,这也使得SQLite较为轻量级.当一个连接要写数据库时,所有其它的连接都被锁住,直到 ...
- 【原创】System.Data.SQLite内存数据库模式
对于很多嵌入式数据库来说都有对于的内存数据库模式,SQLite也不例外.内存数据库常常用于极速.实时的场景,一个很好的应用的场景是富客户端的缓存数据,一般富客户端的缓存常常需要分为落地和非落地两种,而 ...
- SQLite学习笔记(六)&&共享缓存
介绍 通常情况下,sqlite中每个连接都会一个独立的pager对象,pager对象中管理了该连接的缓存信息,通过pragma cache_size指令可以设置缓存大小,默认是2000个page,每个 ...
随机推荐
- C#语法糖(Csharp Syntactic sugar)大汇总
首先需要声明的是"语法糖"这个词绝非贬义词,它可以给我带来方便,是一种便捷的写法,编译器会帮我们做转换:而且可以提高开发编码的效率,在性能上也不会带来损失.这让java开发人员羡慕 ...
- iOS滤镜实现之Nashville【instagram】
Nashville是Instagram众多滤镜中最惊艳的一款,独特的奶昔色调赋予照片童话般的唯美感觉.适用范围:营造浪漫唯美的感觉.的确如此啊有2张输入图像 顶点着色有2组坐标NSString *co ...
- ES6笔记(3)-- 解构赋值
系列文章 -- ES6笔记系列 解构赋值,即对某种结构进行解析,然后将解析出来的值赋值给相关的变量,常见的有数组.对象.字符串的解构赋值等 一.数组的解构赋值 function ids() { ret ...
- SQ--模糊查询
Between..And --between...and...在数据库内部是做作特殊优化的,执行效率比> and<等这种方式快:--between a and b 相当于:字段>=a ...
- 使用LinkedList模拟一个堆栈或者队列数据结构
使用LinkedList模拟一个堆栈或者队列数据结构. 堆栈:先进后出 如同一个杯子. 队列:先进先出 如同一个水管. import java.util.LinkedList; public cl ...
- 用php怎么写一个用户注册登录的页面呢?
想写就会尽快去写.如果用php写了就一定要用nodejs写出来啊,不写是小狗啊! 补充一下,想要实现的功能: 1.用户名重复检测 2.检测信息填写是否完整 3.邮箱是否已经被注册 4.实现ajax无刷 ...
- jquery的promise实践--连续加载图片
在javascript设计模式实践之代理模式--图片预加载中用代理模式实现了图片预加载功能. 现在就更进一步,完成一个能够一张一张的连续图片加载的功能. 功能: 1.一张一张加载图片. 2.加载错误, ...
- JQuery对ASP.NET MVC数据进行更新删除
以前学习ASP.NET MVC时,学习与应用,操作过数据显示,添加,编辑,更新和删除等功能. 很多方法是相通的,看自己是怎样来进行方便,快捷,高效率. 今天Insus.NET写的练习,是直接对绑定在T ...
- HoverTree项目添加了查看留言列表功能
HoverTree项目添加了查看留言列表功能 页面:HoverTreeWeb项目下hvtpanel/usermessage/messagelist.aspx 添加留言页面:addmessage.asx ...
- LeetCode122:Best Time to Buy and Sell Stock II
题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...