拆开 AnkiSQLite 数据库里藏着你的整个记忆系统【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki在绝大多数人的认知里Anki 是一个背单词软件正面问题、背面答案、按遗忘曲线弹出复习卡片。但在工程师的视角下这个判断错得离谱。Anki 真正在做的事情是把记忆建模成一套可读、可写、可分析的数据结构——每一次点击认识/不认识/模糊都在更新一组精心设计的数字而承载这一切的只是一个再普通不过的 SQLite 文件。这就是为什么社区里反复出现同一个论断Anki 不是背单词工具而是一套基于间隔重复的认知操作系统。这句话并非修辞。当你把 collection.anki2 拖进任意一个 SQLite 查看器你会看到一张几乎可以直接读懂的记忆工程蓝图。本文不再停留在使用层面而是直接拆开这个文件看看你的整个记忆系统到底是如何被存下来的。五张表就是记忆系统的全部家当Anki 的数据库 schema 定义在仓库的 rslib/src/storage/schema11.sql 中。整个系统只有五张核心表col、notes、cards、revlog、graves。五张表之间靠整型外键连接构成一条清晰的数据链路。col单行的元数据表保存集合的创建时间、修改时间、schema 版本、同步序号以及序列化成 JSON 的全局配置、牌组、笔记类型与模板notes笔记Note即你录入的问题-答案原文字段以\x1f单位分隔符拼接存储cards卡片Card笔记通过模板实例化出的复习单元也是调度算法的直接作用对象revlog复习日志每一次答题的完整记录是整个系统最有价值的数据资产graves删除墓碑记录哪些对象被删过供同步时把删除操作传播到其他设备。理解这张表结构就理解了 Anki 的第一个设计决策内容与调度彻底分离。你编辑笔记内容不影响任何调度数据你重新排列牌组也不触碰笔记原文。notes与cards通过nid关联一条笔记可以派生多张卡片ord字段标明它对应模板中的第几个这正是一个知识点多角度考察的底层支持——见 rslib/src/storage/card/mod.rs 中all_cards_of_note的实现。cards 表一张卡片的内存画像cards表的每一行都是一个独立记忆单元的当前状态快照。看它的字段定义调度算法的全部状态机就暴露无遗CREATE TABLE cards ( id integer PRIMARY KEY, nid integer NOT NULL, -- 所属笔记 did integer NOT NULL, -- 所属牌组 ord integer NOT NULL, -- 模板序号 type integer NOT NULL, -- 卡片类型 queue integer NOT NULL, -- 当前队列 due integer NOT NULL, -- 到期时间 ivl integer NOT NULL, -- 间隔 factor integer NOT NULL, -- 简易度 reps integer NOT NULL, -- 复习次数 lapses integer NOT NULL, -- 遗忘次数 ... );字段的枚举语义定义在 rslib/src/card/mod.rs。type卡片类型只有四档New0、Learn1、Review2、Relearn3而queue队列则精细得多——New0、Learn1、Review2、DayLearn3、PreviewRepeat4还有三个负值代表不可用状态Suspended-1暂停、SchedBuried-2调度原因被搁置、UserBuried-3手动搁置。负值的设计让不可用状态天然排在任何正常队列之后索引查询无需额外条件。due字段的语义随队列变化新卡片存位置号、学习中的卡片存 Unix 时间戳精确到秒、复习中的卡片存距集合创建日的天数。这样一个字段用三种编码换来的是调度查询可以全部走索引——rslib/src/storage/card/due_cards.sql 中那条取到期卡片的 SQL核心条件不过queue ? AND due ?两行。factor存的是放大 1000 倍的简易度2500 表示 250%ivl用正负号区分天与秒两种粒度正数按天、负数按秒见 rslib/src/revlog/mod.rs 中的注释。复习次数reps、遗忘次数lapses也直接落表浏览器里该卡片已复习 37 次、遗忘 5 次的统计不过是两次列求和。值得一提的是新版 Anki 把 FSRS 的记忆状态稳定度、难度、期望保留率、衰减系数、上次复习时间序列化进cards.data这个 JSON 列由 rslib/src/storage/card/data.rs 中的CardData结构负责读写。数据库为了支持这些新维度在 rslib/src/storage/sqlite.rs 里注册了一批自定义 SQL 函数比如extract_fsrs_variable(data, s)直接提取稳定度、extract_fsrs_retrievability(...)在 SQL 层计算当前可提取率。这意味着按记忆难度排序复习这类需求可以写成一条普通 SQL 完成——把算法推理下沉到数据库层是 Anki 后期架构一个很深的优化。revlog一份被大多数人忽视的行为日志如果说cards是记忆系统的当前态revlog就是它的全量操作日志。每一次按键答题都会向这张表追加一条记录CREATE TABLE revlog ( id integer PRIMARY KEY, -- 毫秒级时间戳天然有序 cid integer NOT NULL, -- 卡片 ID ease integer NOT NULL, -- 按下的按钮1-40 表示手动重排 ivl integer NOT NULL, -- 本次给出的新间隔 lastIvl integer NOT NULL, -- 上次间隔 factor integer NOT NULL, -- 答题后的简易度/难度 time integer NOT NULL, -- 本次答题耗时毫秒 type integer NOT NULL -- 复习类型 );type的语义远比复习/学习丰富Learning0、Review1、Relearning2、Filtered3过滤牌组中的提前复习旧版叫 Cram、Manual4手动设置到期日、Rescheduled5FSRS 重排。这一枚举定义在 rslib/src/revlog/mod.rs。这张表的价值在于它是你全部学习行为的历史档案且永不因复习而覆盖。你一周前对某张卡片的迟疑、某天深夜连续三次的忘记都完整留在revlog里。今天统计页上每一张折线图全部由这张表驱动——rslib/src/stats/graphs/mod.rs 中graph_data()把revlog一次性读入内存然后分别计算复习量、保留率、间隔分布、按钮分布、时段分布studied_today则是 rslib/src/storage/revlog/studied_today.sql 里一条按时间窗过滤的聚合查询。甚至在打开卡片信息面板时rslib/src/stats/card.rs 会回放这张卡片的全部revlog条目重建它每一次复习前后的记忆状态。把复习数据当产品数据来分析Anki 给出的答案是每一张卡片都是一个用户revlog是埋点日志cards是实时状态表。统计功能不是事后拼装的营销看板而是从第一天就写进 schema 的核心设计。这也解释了为什么社区文章反复提醒不要轻易清空复习记录——那不只是删数据而是销毁了算法和个人学习史的完整证据链。本地优先一个普通文件给用户的底气Anki 把全部数据装进一个单文件 SQLite这不是妥协而是刻意选择。它带来的第一个直接红利是数据主权不需要登录、不需要联网、不需要担心服务商关停你的记忆备份就是复制粘贴一个.anki2文件。文件即接口这也催生了庞大的第三方生态——CSDN 上的评测文章反复强调 Anki 的数据控制权和开源架构根源就在这里。第二个红利是工程上的可靠性。看 rslib/src/storage/sqlite.rs 中打开数据库的代码page_size4096、journal_modewal、locking_modeexclusive、显式busy_timeout。WAL 模式让读操作不阻塞写操作复习界面滚动时后台同步写入不会卡顿checkpoint()方法负责把 WAL 中的内容合并回主库保证复制文件即安全备份。本地优先并不意味着放弃多端同步。schema 里处处为同步留好了接口每张表都有usn更新序号列本地修改标记为 -1同步后由服务端替换为全局递增序号见 rslib/src/storage/sync.rsgraves表专门记录删除操作让删卡片这件事也能跨设备传播。更妙的是版本管理col.ver记录 schema 版本仓库里保存了从 schema 11 到 18 的整套升级/降级脚本见 rslib/src/storage/upgrades 目录例如 schema18_upgrade.sql。新客户端打开旧库会自动升级旧客户端打开新库则自动降级——close()时主动写回旧版本rslib/src/storage/sqlite.rs 中的downgrade_to保证升级了 Anki 之后还能装回旧版。这套双向迁移机制让我的数据永远是我的从口号变成了可验证的行为。还有一处容易被忽略的细节为了支持撤销操作代码里用 SQLite savepoint 充当事务边界注释明说Anki 当前用长事务作为撤销机制。一个学习工具愿意在数据层为撤销付出如此成本恰恰说明它把用户数据当作一等公民来对待。结语记忆系统是数据系统把 Anki 拆到数据层会发现它的核心竞争力从来不是某个算法公式而是一套把认知过程数据化的表结构设计。内容与调度分离、状态快照与操作日志并存、单文件本地存储加双向 schema 迁移——这些决策让记忆第一次变成可导出、可分析、可迁移、可编程的资产。下次在 Anki 里按下一个按钮时不妨想一想你的手指落下的瞬间SQLite 里有一行revlog被写入一张cards记录被更新而整条记忆曲线正沿着这套严谨的数据结构安静地向前延伸。【免费下载链接】ankiAnki is a smart spaced repetition flashcard program项目地址: https://gitcode.com/GitHub_Trending/an/anki创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考