拆开 Anki:SQLite 数据库里藏着你的整个记忆系统

发布时间:2026/10/9 23:24:51

拆开 Anki:SQLite 数据库里藏着你的整个记忆系统 拆开 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),仅供参考
延伸阅读

更多相关文章

2026/10/9 23:24:51

Oracle 19c Windows静默安装实战:从响应文件到排错指南

简介:Oracle Database 19c的Windows x64安装包(WINDOWS.X64-193000-gsm.zip)面向数据库管理员、开发人员及企业IT运维者,用于在Windows平台搭建企业级数据库环境,解决安装部署、性能调优、高可用及安全配置等一线问题。…

2026/10/9 23:19:50

从半加器到四位补码器:加法器与补码电路设计实战

1. 从两个比特开始:半加器为什么是所有加法电路的起点很多人学数字电路的时候,第一个真正动手搭出来的电路就是半加器。它简单到只有两个输入、两个输出,但恰恰是这种简单,让它成为理解整个加法器体系最好的入口。半加器要解决的问…

2026/10/9 23:19:50

TinyML开发板选型指南:内存、算力、功耗与工具链的平衡之道

1. 从“跑个模型”到“塞进指甲盖”:TinyML硬件选型的底层逻辑很多人第一次接触TinyML,脑子里想的都是“把模型压缩一下,往单片机里一塞就完事了”。我刚开始也是这么想的,结果拿了一块常见的Cortex-M4开发板,把Tensor…

2026/10/10 0:24:57

航拍滑坡目标检测实战:从VOC转YOLO到滑窗推理的完整指南

简介:面向滑坡灾害识别与遥感目标检测研究者,这份航拍影像数据集以VOC与YOLO两种格式提供目标检测标注,可直接用于YOLO系列等主流检测模型的训练,适用于地质灾害监测、应急救援等视觉任务的前期研究。压缩包共2000个文件&#xff…

2026/10/10 0:24:57

Fluent水密工作流中的Add Boundary Layers:参数详解与实操指南

做 CFD 的人多半都经历过这种尴尬:表面网格怎么检查都漂亮,体网格一生成就崩,或者残差卡在 1e-3 死活下不去,最后翻来覆去发现是近壁面那圈网格在捣鬼。在 Fluent 的水密工作流里,专门负责处理这一圈的就是 Add Bounda…

2026/10/10 0:24:57

脑电情绪分析系统:从数据预处理到跨被试验证的技术要点

简介:面向脑电信号分析与情绪识别的研究者和开发者,这套源码基于PythonHTML,覆盖信号预处理、特征提取、模型训练到前端展示的完整流程。压缩包共49个文件、约11.51MB,包括8个HTML页面、6个Python源文件、6个XML配置、4个PyTorch模…

2026/10/10 0:24:57

微信小程序地图开发实战:定位、坐标系与权限避坑全攻略

微信里的地图功能,看着就是个“发位置”“看导航”的小工具,但真把它玩明白的人不多。从日常找人、共享实时位置,到小程序里做门店展示、打卡签到,这些功能背后其实藏着一整套体系。我最近刚好把一个和微信地图相关的小程序项目从…

2026/10/10 0:24:57

别只看视力表:青少年眼疲劳的真相与科学缓解策略

2. 青少年眼疲劳的真相:你的眼睛正在经历什么2.1 眼疲劳不只是"累",而是肌肉的无声呼救很多孩子觉得眼睛酸胀、干涩、看东西模糊,休息一下就好了,但很少人真正理解这背后发生了什么。人眼要看清楚近处物体,靠…

2026/10/10 0:19:56

Codex+ChatGPT 对比 TRAE+DeepSeek:TaoToken 统一 Key 下的实测感受

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/9 20:15:56

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:04:53

从逻辑门到计算机:数字电路核心原理与全加器搭建实战

如果你拆过一台旧电脑的主板,盯着那些黑乎乎的小芯片看上一会儿,可能会冒出同一个疑问:这堆引脚密集的元件,到底是怎么“变”出那么复杂的应用的?答案并不在某个神秘的部件里,而是在所有芯片内部都在反复使…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑