闪存

对象序列化系列

数据序列化系列(待更)

《Android 数据序列化之 JSON》

《Android 数据序列化之 Protocol Buffer 使用》

《Android 数据序列化之 Protocol Buffer 源码分析》

SQLite 存储系列

SQLite WAL 模式工作原理分析

什么是 WAL

WAL 的全称是 Write Ahead Logging(预写日志),它是很多数据库中用于实现原子事务的一种机制。SQLite 在 3.7.0 版本引入该特性,在此之前 SQLite 实现原子提交和回滚的方法是 rollback journal(回滚日志)。

WAL 工作原理

Rollback Journal

SQLite 在引入 WAL 模式之前,使用的是 Rollback Journal 机制实现原子事务。Rollback Journal 的原理是,在修改数据库文件中数据之前,先将修改所在分页中的数据备份在另外一个地方,然后才将修改写入到数据库文件中;如果事务失败,则将备份数据拷贝回来,撤销修改;如果事务成功,则删除备份数据提交修改。

WAL

WAL 的方法正好反过来了,原始内容保留在数据库文件中,修改数据而是写入到另外一个称为 WAL 的文件中,如果事务失败,WAL 中的记录会被忽略,撤销修改;如果事务成功,它将随后的某个时间被写回到数据库文件中,提交修改。

同步 WAL 文件和数据库文件的行为被称为 CheckPoint(检查点)。

在读数据库时,SQLite 将在 WAL 文件中搜索,找到最后一个写入点,记住它,并忽略在此之后的写入数据(这保证了读和写可以并发执行);随后它确定所要读的数据所在页是否在 WAL 文件中,如果在,则读 WAL 文件中的数据,如果不在,则直接读数据库文件中的数据。

在写入数据库时,SQLite 将数据写入到 WAL 文件中即可,但是必须保证独占写入,因此写和写之间不能并发执行。WAL 在实现的过程中,使用了共享内存技术,因此所有的读写进程必须在同一个机器上,否则无法保证数据的一致性。

检查点

当然,最终希望将 WAL 文件中附加的所有事务转移回原始数据库。将 WAL 文件事务移回数据库称为“检查点”。

考虑回滚日志和预写日志之间差异的另一种方法是,在回滚日志方法中,存在两种原始操作,即读取和写入,而对于预写日志,此时会有三种原始操作:读取、写入和检查点。

默认情况下,当 WAL 文件达到 1000 页的阈值大小时,SQLite 自动执行一个检查点。使用 WAL 的应用程序不需要执行任何附加操作即可享受到 CheckPoint。但是如果需要应用程序调整自动检查点阈值,可以使用 SQLITE_DEAULT_WAL_AUTOCHECKPOINT 编译时选项指定其它默认值。

并发

在 WAL 模式数据库上开始读数据库操作时,它首先会记住 WAL 中最后一个有效提交记录的位置。将此点称为“结束标记”。由于 WAL 可以在各种读取器连接到数据库的同时不断增长并添加新的提交记录,因此每个读取器都可能具有自己的结束标记。但是对于任何特定的读取,结束标记在事务期间不会改变,从而确保了单个读取事务只能看到数据库内容,因为它存在于单个时间点。

当读取需要一页内容时,它首先检查 WAL 以查看读取页面是否出现在该页面中,如果是,它将拉入 WAL 中出现在读者终点标记之前的页面的最后副本。如果在 WAL 中没有页面的副本位于读者的结尾标记之前,则从原始数据库文件中读取页面。读取可以存在于单独的进程中,因此避免强迫每个读取扫描整个 WAL 寻找页面(WAL 文件可以增长到数兆字节,具体取决于运行检查点的频率),这种数据结构成为“wal-index”保留在共享内存中,这有助于读取以最少的 I/O 速度在 WAL 中定位页面。wal-index 大大提高了读取的性能,但是共享内存的使用意味着所有读取者必须在同一台计算机上。

写入者仅将新内容附加到 WAL 文件的末尾。因为写入不做任何会干扰读取数据行为的事情,所以写和读可以同时运行。但是,由于只有一个 WAL 文件,所以一次只能有一个写入器。

检查点操作从 WAL 文件中获取内容,并将其回传到原始数据文件中。检查点可以与读取任务同时运行,但是当检查点到达 WAL 中的页面,超过任何当前读取任务的结束标记时,必须停止。检查点必须在该点处停止,因为它可能会覆盖读取者正在使用的部分数据库文件。该检查点会记住(wal-index中)到达的距离,并继续将内容从 WAL 传输到下一次调用中断位置的数据库。

因此,长时间运行的读取事务可能会阻止检查指针运行。但是大概每个读取事务最终都会结束,并且检查指针将能够继续。

每当发生写操作时,写入者都会检查指针取得了多少进展,如果整个 WAL 已传输到数据库并进行了同步,并且如果没有读取正在使用 WAL,则写入者将 WAL 重新从 0 开始,并在 WAL 开始时进行新交易。这种机制可以防止 WAL 文件无限制地增长。

性能问题

写事务非常快,绝大多数情况下,WAL 会提高 SQLite 的事务性能,因为它们只涉及一次写入内容(相对回滚日志事务而言则是两次),而且写入都是顺序的。但是在某些极端情况下,却会导致 SQLite 事务的性能下降。

但是随着 WAL 文件大小的增加,读取性能会下降,因为每个读取任务都必须检查 WAL 文件中的内容,并且检查 WAL 文件所需要的时间与 WAL 文件的大小成正比。wal-index 有助于更快地在 WAL 文件中查找内容,但是性能随着 WAL 文件大小的增加而下降。因此为了保持良好的读取性能,要通过定期运行检查点来减小 WAL 文件的大小。

检查点确实需要同步操作,以避免断点或硬重启后数据库损坏的可能性。在将内容从 WAL 移到数据库之前,必须将 WAL 同步到持久性存储,并且在重置 WAL 之前必须同步数据库文件。CheckPoint 还需要更多寻求。检查指针会尽最大努力对数据库进行顺序的页面写入,但是即使这样,页面写入之间通常也会散布着许多查找操作。这些因素共同导致检查点比写入事务慢。

默认策略是允许连续的写事务增长 WAL,直到 WAL 变为大约 1000 页,然后为每个后续 COMMIT 运行检查点操作,直到 WAL 重置为小于 1000 页为止。默认情况下,检查点将由执行 COMMIT 的同一线程自动运行,该线程是 WAL 超过其大小限制。这会导致大多数 COMMIT 操作非常快,但偶尔的 COMMIT(触发检查点的操作)会慢的多。如果不希望这种影响,则应用程序可以禁用自动检查点,并在单独的线程或单独的进程中运行定期检查点。

WAL 的优点与缺点

优点:

读操作不会阻塞写操作,同时写操作也不会阻塞读操作。这是并发管理的“黄金准则”。

在大多数操作场景中,与回滚日志相比,WAL 相当快。

磁盘 I/O 变得更可预见,更少的 fsync 系统调用,因为所有的 WAL 写操作是线性写入日志文件,很多 I/O 变的连续并能够按计划执行。

缺点:

所有的处理被绑定到单个主机上。也就是说,不能再如 NFS 这样的网络文件系统上使用 WAL。

为满足 WAL 和相关共享内存的需要,使用 WAL 引入了里两个额外的半持久性文件-wal 和-shm。对于那些使用SQLite 数据库作为应用程序文件格式是不具有吸引力的。这也影响了只读环境,因为-shm文件必须是可写的,并且/或数据库所在目录也必须是可写的。

对于非常大的事务,WAL 的性能将会降低。虽然 WAL 是一个高性能选项,但是非常大或运行时间非常长的事务会引入额外的开销。

WAL模式 Android,SQLite 数据库 WAL 工作模式原理简介相关推荐

  1. Android SQLite数据库版本升级(分逐级升级和跨版本升级)

    参考:Android Sqlite数据库跨版本升级 保存之前数据 本文说的数据库升级是基于Android原生APISQLiteOpenHelper实现的逻辑,不涉及第三方库.其实如果使用官方推荐的Ro ...

  2. android SQLite数据库的使用

    今天,简单讲讲android如何使用SQLite数据库.  最近,自己在做一个功能时又用到了SQLite数据库,发现自己还是掌握的不很全面.其实之前的app里面也一直用到了数据库,但是自己没有花时 ...

  3. Android Sqlite数据库多表联合查询

    Android Sqlite数据库多表联合查询示例 工作上用数据库存储文件还是很便利的,所以有时候发现一张表存储数据感觉数据结构不是很清晰的时候,就需要新加第二张表或者多张表来进行联合查询对象信,一般 ...

  4. android 数据库表格数据库数据库中,Android SQLite数据库中的表详解

    Android SQLite数据库 前言 以前写PHP的时候,内置了print_r()和var_dump()两个函数用于打印输出任意类型的数据内部结构,现在做Android的开发,发现并没有这种类似的 ...

  5. 利用SQLChiper对Android SQLite数据库加密

    利用SQLChiper对Android SQLite数据库加密 前言: 上篇文章讲了Android studio+SQLCipher加密SQLite数据库的几个坑,跳过这几个坑,那么SQLCipher ...

  6. Android SQLite 数据库详细介绍

    Android SQLite 数据库详细介绍我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用软 ...

  7. android 获取位置数据库,尝试从webview获取位置时,Android“SQLite数据库无法从/CachedGeoposition.db加载”错误...

    我正在创建一个使用webkit和chrome客户端的android应用程序.我希望能够在网页请求时获取当前位置.我设置的网页适用于普通浏览器就好了.然而,当我尝试访问该网页WebKit中,我不断收到此 ...

  8. Android SQLite数据库导出/导入Excel

    Android SQLite数据库导出/导入Excel 前言 框架 使用方法 添加依赖 声明权限 导出数据库到Excel 声明实例 配置导出内容 导出监听 导入Excel到数据库 声明实例 导入监听 ...

  9. android sqlite数据库加密,(转)SQLite数据库的加密

    1.创建空的SQLite数据库. //数据库名的后缀你可以直接指定,甚至没有后缀都可以 //方法一:创建一个空sqlite数据库,用IO的方式 FileStream fs = File.Create( ...

最新文章

  1. 四川职业学校计算机专业那个好6,四川排名前六的单招学院那些专业比较好?
  2. [comparator] 策略模式
  3. pandas中loc、iloc与ix的用法比较
  4. 【华为云技术分享】CentOS7.4系统下,手动安装MySQL5.7的方法
  5. Hadoop(一)基础概念
  6. Ubuntu中出现“Could not get lock /var/lib/dpkg/lock”的解决方法
  7. perl oracle ppm,Perl图形化包管理工具PPM学习使用笔记
  8. 2017.9.6.语文
  9. 生态功能区划方法之一:生态敏感性分析法
  10. linux测试libreoffice,LibreOffice 7.0 开放测试,最终版本将于8月初发布
  11. 修复 Mac 上“未找到 AirPrint 打印机”的错误
  12. VS code react插件快捷键
  13. 微软Windows 8 非常实用的12个技巧
  14. Android chrome默认设置Autoplay policy
  15. Altium designer (AD)中如何设置区域规则和器件规则
  16. linux生成秘钥库,在Linux中,生成强预共享密钥(PSK )的4种方法
  17. 纯js图片验证码Captcha.js
  18. 25岁德邦被京东收购,网友:这次。。。
  19. 【前端之旅】Web前端发展简史
  20. 调节阀卡塞的处理方法

热门文章

  1. vue安装node-sass问题解决
  2. 各大互联网公司新年礼盒大比拼,看完觉得自己太惨了!
  3. python中的xlrd模块_python:xlrd模块
  4. jdb java 变量编号_jdb 调试java
  5. 网络安全这玩意儿真不建议一般人学...
  6. 前端页面支持水印动态配置需求实现建议
  7. 电大计算机dm编写程序,电大数控编程技术课后习题答案.doc
  8. 直观了解图片的三通道像素值在三维数组中的表示(python)
  9. 科研管理系统使用手册
  10. python——商业按揭贷款分析