一个本地NMB数据阅读器无名氏No.68758003 只看PO
2026-06-01(一)18:07:05 ID:SLDLTVR 回应
最开始只是想给大洛山的串留个档,然后
下都下了,整个本地阅读器吧( ´∀`)
整都整了,做个服务器版吧,手机就也能看了( ゚∀゚)
做都做了,把检索也加上吧( ゚ 3゚)
加都改加了,把整个流程改完整点吧(ゝ∀・)
现在觉得整这么麻烦为啥我不直接上岛看了(*゚ー゚)
总之这是个从下载数据到双端阅读的NMB阅读器|-` )
无标题无名氏No.68811857
2026-06-09(二)11:00:19 ID: SLDLTVR (PO主)
要不你直接问AI吧,你们俩的细节解释的我都不太懂(;´ヮ`)7
后端我真不会啊(つд⊂)
不过我是觉得你直接定就好了( ゚ 3゚)
无标题无名氏No.68811900
2026-06-09(二)11:07:18 ID: SLDLTVR (PO主)
>>No.68811867
别的没了,对TEXT这块AI原文是
TEXT 不会因为类型叫 TEXT,就天然变成“大量随机 IO”。真正决定 IO 的是:
你怎么查
一次查多少行
数据库怎么存储长字段
这些正文是不是被频繁读
先说结论
如果你的页面是“先按索引找一页 post_no,再把这一页对应的 content 读出来”,TEXT 完全正常
真正容易带来 IO 压力的,不是 TEXT 这个类型本身,而是“正文很大、读得很频繁、而且每次查很多不需要的正文”
你的场景里要点是
目录页不要扫正文
目录页只查 thread / tag / status / installment / count 这些轻字段,不碰 content,IO 就很轻。
阅读页按页取少量帖子正文
比如一次只取 20/50 条,这也没问题。
你本来就是要把正文显示出来,这部分 IO 无论 VARCHAR(8192) 还是 TEXT 都躲不掉。
不要在大范围筛选里直接扫 content
如果你以后做全文搜索,别用普通 LIKE '%xxx%' 去硬扫大表。
那才是真的 IO 杀手。要么上全文索引,要么单独做搜索方案。
为什么 VARCHAR(8192) 也不能避免这个问题
就算你把列定义成 VARCHAR(8192):
里面存的还是长正文
读正文时照样要把正文拿出来
所以 IO 压力本质没变
也就是说:
TEXT 不是问题来源
“频繁扫描大正文”才是问题来源
如果你担心 IO,可以这样设计
post 表只放轻字段和定位字段
post_content 单独放 content
列表、筛选、分页尽量先走轻表
只有真正打开阅读页时,才按当前页 post_id 去取正文
其实你现在这个“索引表 + 正文表”思路,本身就是在避免不必要的正文 IO,这个方向是对的。
一句话
TEXT 不会天然导致大量随机 IO;
真正导致大量 IO 的,是把正文当索引字段去大范围扫描。
你这种阅读器场景,只要“目录查轻字段、阅读页按页取正文”,TEXT 是合适的。
无标题无名氏No.68812311
2026-06-09(二)12:11:16 ID: gEGGVQn
>>No.68811907
我整理完
TABLE post -- 存储所有post,包括串首,特别地,串首page_num = 0
-- post表只会发生插入,不会发生删除或更改
thread_id, INT -- 串首串号
id, INT -- 本条post串号,全局唯一,特别地,串首id = thread_id
cookie, CHAR(7)
page_num, INT -- 保持岛原有页码结构,不会发生更改
is_po, BOOL
is_sage, BOOL
is_admin, BOOL
created_at, UINT
PRI(thread_id, id) -- 用于快速访问串内所有post
KEY(thread_id, page_num) -- 用于串内随机访问某页
KEY(thread_id, cookie) -- 用于串内查找某个cookie的发言
KEY(cookie, id) -- 用于查找某个cookie的所有发言
KEY(id) -- 用于快速获取引用
TABLE thread -- 存储所有串首数据
thread_id, INT
cookie, CHAR(7)
replies, INT -- 该串首下的回复数量
is_sage, BOOL
is_admin, BOOL
installment, DECIMAL -- 展示用的系列内写作顺序,可能有间章
created_at, UINT
PRI(thread_id)
KEY(cookie) -- 用于查找某个cookie发的所有串
KEY(replies) -- 按热度排序
KEY(created_at) -- 按发布时间排序
KEY(cookie, created_at) -- 某个cookie发布的串按发布时间排序
TABLE post_content
id, INT
thread_id, INT
cookie, CHAR(7) -- 用于可能的以后manticore建立倒排索引
content, TEXT
img, VARCHAR(128) -- 图片在本地存储的相对位置
title, VARCHAR(64)
name, VARCHAR(64)
created_at, UINT
PRI(thread_id, id) -- 内容按串在磁盘上邻近排列便于读取
KEY(id) -- 用于快速获取引用
TABLE thread_content -- 用于可能的以后manticore只检索串首的功能
thread_id, INT
cookie, CHAR(7)
content, TEXT
img, VARCHAR(128)
title, VARCHAR(64)
name, VARCHAR(64)
created_at, UINT
PRI(thread_id)
TABLE tag_registry
tag_id, INT
tag_type, VARCHAR(64) -- 如“serie”、“status”
tag_name, VARCHAR(64) -- 如“大洛山系列”、“连载”
PRI(tag_id) AI
UNI(tag_type, tag_name)
TABLE thread_tag
thread_id, INT
tag_id, INT
tag_type, VARCHAR(64)
single_type, VARCHAR(64) VIRTUAL
/*
single_type VARCHAR(64) GENERATED ALWAYS AS (
CASE
WHEN tag_type = 'CUSTOM_TAG' THEN NULL
ELSE tag_type
END
) VIRTUAL
*/
PRI(thread_id, tag_id)
UNI(thread_id, single_type)
KEY(tag_id, thread_id)
然后才想起来
1.我们是不是还该做一个屏蔽某个cookie的功能
2.写完就忘了,待会想起来再说
无标题无名氏No.68812349
2026-06-09(二)12:17:05 ID: gEGGVQn
>>No.68812311
想起来了,我想的是,我现在两个content表里面的冗余数据都是为了manticore能直接从这一个表导入设计的,但是现在越来越冗余,我在想还值不值得,还是说之后用JOIN导入,现在就不要设计这么冗余了?
无标题无名氏No.68812635
2026-06-09(二)13:07:21 ID: SLDLTVR (PO主)
>>No.68812311
是要从写数据库开始就屏蔽某些cookie吗
感觉在前端留给用户自己填屏蔽的饼就行
然后冗余的字段如果只是没必要而不是有负面影响的话,我觉得就先保留。删掉某一字段应该比之后想追加的时候,重新加数据容易吧( ゚ 3゚)
无标题无名氏No.68812678
2026-06-09(二)13:15:28 ID: gEGGVQn
我新整理的是
TABLE post -- 存储所有post,串首是一个特殊的post,特别地,串首page_num = 0
-- post表只会发生插入,不会发生删除或更改
thread_id, INT -- 串首串号
id, INT -- 本条post串号,全局唯一,特别地,串首id = thread_id
cookie, CHAR(7)
page_num, INT -- 保持岛原有页码结构,不会发生更改
is_po, BOOL
is_sage, BOOL
is_admin, BOOL
created_at, INT UNSIGNED -- 这条post发布的时间,保证与id保持单调非递减,具体地,对于A.id < B.id,则A.created_at <= B.created_at
PRI(thread_id, id) -- 用于快速访问串内所有post,且保证每个串的所有post在物理存储上相邻
KEY(thread_id, page_num) -- 用于串内随机访问某页
KEY(thread_id, cookie) -- 用于串内查找某个cookie的发言
KEY(cookie, id) -- 用于全局查找某个cookie的发言
UNIQUE KEY(id) -- 用于快速获取引用
-- created_at排序与id排序在时间意义上一致
TABLE thread -- 存储所有串首数据
thread_id, INT
cookie, CHAR(7)
replies, INT -- 该串的回复数量
is_sage, BOOL
is_admin, BOOL
installment, DECIMAL(5,2) -- 展示用的系列内写作顺序,可能有间章
created_at, INT UNSIGNED -- 保证与thread_id保持单调非递减
PRI(thread_id)
KEY(replies) -- 按热度排序
KEY(cookie) -- 某个cookie的串
-- created_at排序与thread_id排序在时间意义上一致
TABLE post_body
id, INT
thread_id, INT
content, TEXT
img, VARCHAR(255) -- 图片在本地存储的相对位置
title, VARCHAR(64)
name, VARCHAR(64)
PRI(thread_id, id) -- 使内容按串在磁盘上邻近排列便于读取
UNIQUE KEY(id) -- 用于快速获取引用
TABLE tag_registry
tag_id, INT
tag_type, VARCHAR(16) -- 如“serie”、“status”
tag_name, VARCHAR(64) -- 如“大洛山系列”、“连载”
PRI(tag_id) AI
UNI(tag_type, tag_name)
TABLE thread_tag
thread_id, INT
tag_id, INT
tag_type, VARCHAR(16)
single_type, VARCHAR(16) VIRTUAL
/*
single_type VARCHAR(16) GENERATED ALWAYS AS (
CASE
WHEN tag_type = 'CUSTOM_TAG' THEN NULL
ELSE tag_type
END
) VIRTUAL
*/
PRI(thread_id, tag_id)
UNI(thread_id, single_type)
KEY(tag_id, thread_id)
删掉了thread_body和一些原本打算用来给manticore单表导入设计的冗余内容,之后导入的时候就JOIN吧
我是觉得没什么需要改的了