nt_msg.db 是 NTQQ 存贮聊天记录本体的数据库:消息行、会话列表、未读状态都在这里。
本栏目的内容全部由 WeQ 依据自己的解析实现手写维护。
| 表 | 内容 | 文档 |
|---|---|---|
c2c_msg_table |
好友单聊消息 | 消息行 |
group_msg_table |
群聊消息(结构同 c2c,多 40062 贴表情列) | 消息行 · 40062 |
dataline_msg_table |
数据线消息(我的手机 / 电脑 / 平板,结构同 c2c) | 消息行 |
recent_contact_v3_table |
会话列表 | recent-contact |
recent_contact_top_table |
置顶会话 | recent-contact-top |
hidden_session_storage_table_v1 |
隐藏会话 | hidden-session |
recent_contact_delete_storage |
删除会话 | deleted-session |
msg_unread_info_table |
未读信息 + 提醒高亮 | unread-info |
nt_uid_mapping_table |
uid ↔ uin ↔ sortNo 目录 | 下见 |
draft_storage_table_v1 |
草稿:输入了但还没点发送的内容(WeQ 读写) | draft-storage |
三张消息表的列布局完全一致,差别只在会话分区键(c2c 按 sortNo 分区、群按群号)。 逐列的字段表见 消息行解析;一行里最复杂的几个列:
| 列 | 名称 | 结构 | 说明 |
|---|---|---|---|
| 40800 | 消息正文(MsgBody) | repeated ElementWire |
一条消息的富文本消息段序列,见 40800 解析 |
| 40801 | 消息装扮信息 | MsgDressBody |
气泡 / 聊天字体 / 挂件等装扮信息,见 40801 解析 |
| 40900 | 消息缓存(MsgCache) | repeated MsgCache(可递归嵌套) |
转发/引用时缓存的源消息快照,见 40900 解析 |
| 40062 | 贴表情(仅群聊) | repeated EmojiSticker |
群消息上的表情回应,见 40062 解析 |
📖 建议先读 40800 解析 的前半部分 —— 「扁平信封」与「文件族共用字段」 两节是理解所有消息段的前提,各消息段文档不再重复这些内容。
账号级的身份目录,三列:
| 列 | 含义 |
|---|---|
| 48901 | sortNo —— 该账号给每个交互过的对端分配的 1 起递增小整数 |
| 48902 | uid —— 其它地方通用的不透明对端标识 |
| 1002 | uin —— 对端 QQ 号 |
它之所以重要:c2c_msg_table 的会话分区列是 40027(= 这里的 sortNo),
所有有用的复合索引都建在它上面((40027,40003) 等);而应用层是按 uid 找会话的,
40021 恰恰没有索引。所以走快路径查 c2c 消息,必须先 uid → sortNo 翻译一次。
这张表很小且稳定,WeQ 在会话启动时整表读进内存(UidMap)常驻。
QQ 给两张消息表建的复合索引全部以会话键打头((40027,40003)、(40027,40058)…)。
这对「按会话翻消息」是够的,但跨全库、按时间窗的统计(年度报告)一条都用不上 ——
只能全表扫描并回表。WeQ 因此在开账号后于后台就地补两个覆盖索引:
| 索引名 | 表 | 列 | 服务于 |
|---|---|---|---|
weq_annual_sendtime_dir_group |
group_msg_table |
(40050,40040) |
年度报告第一页 / 历史以来的方向计数 |
weq_annual_sendtime_dir_c2c |
c2c_msg_table |
(40050,40040) |
同上(私聊侧) |
过滤列(sendTime)与取值列(sentSource)都在索引里,查询退化成一次索引区间扫描,
不再碰表本体(实测 200 万行 / 2GB:0.9s → 0.06s)。这与搜索的 FTS 索引
不是一回事:那个是内容副本 + 倒排,只能落在 WeQ 自己的派生库里;这两个是就地
CREATE INDEX 的普通 B-tree,SQLite 自己维护,QQ 写入时自动更新,WeQ 没有任何
同步逻辑。
与 QQ 共存的实测结论:schema 只多出两个 index 对象、表结构不动,PRAGMA integrity_check 照常 ok,QQ 运行中 INSERT / UPDATE / DELETE 后索引即时一致;
PRAGMA schema_version 会 +1,但那是 SQLite 每次 DDL 的正常行为,不是 QQ 的校验
指纹(QQ 自己也在持续改它)。代价是每次写入的一点写放大(30 万行插入 1.12s → 1.25s)
与索引占用的空间(约表体的 1–2%)。
与防撤回一样,这属于「WeQ 往 QQ 的实时库里写 DDL」。 只对实时账号生效;导入的静态备份(PC 快照 / 手机备份)不写,保持原样。
40800 由若干消息段(Element)组成,每段以 elementType 区分类型。各类型的字段解析见下;
未观测到的 elementType(12/13/15/17/18/19/20/22/24/25/29/43/44)不单独成篇,
完整枚举见 40800 解析 · elementType 全表。
| elementType | 名称 | 文档 |
|---|---|---|
| 1 | 文本 / @ | text |
| 2 | 图片 | pic |
| 3 | 文件 | file |
| 4 | 语音 | ptt |
| 5 | 视频 | video |
| 6 | 系统表情 | face |
| 7 | 回复引用 | reply |
| 8 | 灰字提示 | gray-tip |
| 9 | 红包 / 转账 | wallet |
| 10 | ARK 卡片 | ark |
| 11 | 商城表情 | mface |
| 14 | Markdown | markdown |
| 16 | 合并转发 | multi-msg |
| 21 | 通话记录 | call |
| 23 | 在线文件 | online-file |
| 26 | 空间动态提示 | qq-dynamic |
| 27 | 弹射表情 | emoji-bounce |
| 28 | 位置共享 | 仅一个字段,见 40800 解析 |
| 30 | 在线文件夹 | online-folder |