写作绅士,读作丧尸 X岛揭示板
顺猴者昌 逆猴者亡 首页版规 |用户系统 |移动客户端下载 | 丧尸路标 | | 常用图串及路标 | 请关注 官方公众号:【X岛揭示板】 官方微博: 【@X岛极速版】| 人,是会思考的芦苇
常用串:·豆知识·跑团板聊天室·公告汇总串·X岛路标

No.68758003 - 一个本地NMB数据阅读器 - 技术宅


回应模式
No.68758003
名 称
E-mail
标题
颜文字
正文
附加图片
•程序语言、压制投稿、视频制作以及各计算机领域的技术问题
•我觉得还是CSDN靠谱一点
•本版发文间隔为15秒。

一个本地NMB数据阅读器 无名氏 2026-06-01(一)18:07:05 ID:SLDLTVR [举报] [订阅] [只看PO] No.68758003 [回应] 管理
最开始只是想给大洛山的串留个档,然后

下都下了,整个本地阅读器吧( ´∀`)
整都整了,做个服务器版吧,手机就也能看了( ゚∀゚)
做都做了,把检索也加上吧( ゚ 3゚)
加都改加了,把整个流程改完整点吧(ゝ∀・)

现在觉得整这么麻烦为啥我不直接上岛看了(*゚ー゚)

总之这是个从下载数据到双端阅读的NMB阅读器|-` )
无标题 无名氏 2026-06-08(一)23:55:17 ID:gEGGVQn [举报] No.68810022 管理
>>No.68809948
我好笨,前面都绕进去了,刚刚想到一个很简单的方案
具体地,标签库表有以下列:
tag_id, INT
tag_type, VARCHAR() -- 如“serie”
tag_content, VARCHAR() -- 如“大洛山系列”
PRI(tag_id)
然后关联表也就是标签表有以下列:
id, INT
tag_id, INT
PRI(id, tag_id)
KEY(tag_id, id)
很漂亮的解决方案
无标题 无名氏 2026-06-08(一)23:56:35 ID:gEGGVQn [举报] No.68810031 管理
>>No.68810016
怎么又是你刚好早我一分钟发,三次了( ゚∀。)我有想过,但是太丑了,可拓展性也被抛弃了
无标题 无名氏 2026-06-08(一)23:58:21 ID:gEGGVQn [举报] No.68810038 管理
>>No.68810016
installment做成tag是要干嘛,你要搜“大洛山系列”我能理解,你搜“第2部”是在干嘛,找有连载的作品吗( ゚∀。)
无标题 无名氏 2026-06-08(一)23:59:46 ID:gEGGVQn [举报] No.68810047 管理
>>No.68810016
而且你这个没做到关联表啊,你这个成多值索引了,虽然不是不能用( ゚∀。)
无标题 无名氏 2026-06-09(二)00:00:03 ID:SLDLTVR (PO主) [举报] No.68810050 管理
>>No.68810038
( ゚∀。)没有没有,是顺手写进去了

>>No.68810022
( ´∀`)bbbb
无标题 无名氏 2026-06-09(二)00:01:42 ID:SLDLTVR (PO主) [举报] No.68810067 管理
>>No.68810047
只是因为我在后端方面过于外行|д` )导致的名词和方案对不上
无标题 无名氏 2026-06-09(二)00:03:03 ID:gEGGVQn [举报] No.68810084 管理
话说po用gpt的话,是用的codex吗?
无标题 无名氏 2026-06-09(二)00:10:21 ID:SLDLTVR (PO主) [举报] No.68810134 管理
>>No.68810084
无标题 无名氏 2026-06-09(二)00:14:10 ID:gEGGVQn [举报] No.68810156 管理
post -- 存储所有post,包括串首,特别地,串首的page_num为0
thread_id, INT
id, INT
cookie, CHAR(7)
page_num, INT
is_po, BOOL
is_sage, BOOL
is_admin, BOOL
PRI(thread_id, id)
KEY(thread_id, page_num) -- 用于串内随机访问某页
KEY(thread_id, cookie) -- 用于串内查找某个cookie的发言
KEY(cookie, id) -- 用于查找某个cookie的所有发言

thread -- 存储所有串首
id, INT
cookie, CHAR(7)
is_sage, BOOL
is_admin, BOOL
installment, FLOAT -- 展示用的系列内写作顺序,可能有间章
PRI(id)
KEY(cookie) -- 用于查找某个cookie发的所有串

post_content
id, INT
thread_id, INT
cookie, CHAR(7)
content, VARCHAR(8192)
img, VARCHAR(128)
title, VARCHAR(64)
name, VARCHAR(64)
created_at, TIMESTAMP
PRI(id)

thread_content
id, INT
cookie, CHAR(7)
replies, INT
content, VARCHAR(8192)
img, VARCHAR(128)
title, VARCHAR(64)
name, VARCHAR(64)
created_at, TIMESTAMP
PRI(id)

tag_registry
tag_id, INT
tag_type, VARCHAR(64) -- 如“serie”、“status”
tag_name, VARCHAR(64) -- 如“大洛山系列”、“连载”
PRI(tag_id) AI
UNI(tag_type, tag_name)

thread_tag
thread_id, INT
tag_id, INT
PRI(id, tag_id)
KEY(tag_id, id)
无标题 无名氏 2026-06-09(二)00:14:49 ID:gEGGVQn [举报] No.68810159 管理
>>No.68810156
你问问AI看看,我想不到别的了( ゚∀。)
无标题 无名氏 2026-06-09(二)00:17:27 ID:SLDLTVR (PO主) [举报] No.68810181 管理
>>No.68810159
(*゚∇゚)bbbbb
行,白天上工位看看GPT还有啥建议没,我感觉也没啥别的了
无标题 无名氏 2026-06-09(二)09:47:11 ID:SLDLTVR (PO主) [举报] No.68811494 管理
给了一堆建议但好多是咱昨天说过的

需要关注一下的就下面几个
1.content用TEXT
2.created_at存INT,UNIX时间戳
3.PRI(id, tag_id),KEY(tag_id, id)这两个应该PRI(thread_id, tag_id),KEY(tag_id, thread_id)
4.installment用NUMERIC这种精确的格式
5.类型、系列那堆加回thread,要不还得验证tag里这些东西是否唯一
无标题 无名氏 2026-06-09(二)10:30:13 ID:gEGGVQn [举报] No.68811701 管理
>>No.68811494
1的理由是什么,text是当前位置存一个指针指向真正的内容,会引发大量随机IO,我认为VARCHAR更好
2的话那就用INT吧,TIMESTAMP确实容易引发一些问题
3是我改列名的时候忘记改了
4我忘了这回事了,改NUMERIC(或者是DECIMAL)确实更好
5的话,首先从应用层我们就该保证一个thread_id只有一个tag_type为serie的tag_id,其次要做的更好的话那就thread_tag结构改成thtead_id, tag_id, tag_type,然后UNI(thread_id, tag_type),具体地,UNIQUE KEY (thread_id, (IF(tag_type = 'CUSTOM_TAG', NULL, tag_type))),tag_registry表结构不变
但是这样的话tag_type冗余存储了一遍,空间不是问题,tag估计最多也就十万级,主要是这样写起来有点丑( ゚∀。)不过这样的设计我觉得挺合理的
无标题 无名氏 2026-06-09(二)11:00:19 ID:SLDLTVR (PO主) [举报] No.68811857 管理
要不你直接问AI吧,你们俩的细节解释的我都不太懂(;´ヮ`)7
后端我真不会啊(つд⊂)

不过我是觉得你直接定就好了( ゚ 3゚)
无标题 无名氏 2026-06-09(二)11:01:53 ID:gEGGVQn [举报] No.68811867 管理
>>No.68811857
那你看看AI还有什么建议没有( ゚∀。)
无标题 无名氏 2026-06-09(二)11:07:18 ID:SLDLTVR (PO主) [举报] No.68811900 管理
>>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 是合适的。
无标题 无名氏 2026-06-09(二)11:08:40 ID:SLDLTVR (PO主) [举报] No.68811907 管理
>>No.68811867
你看着定一下就行了,我信你的(ゝ∀・)
无标题 无名氏 2026-06-09(二)12:11:16 ID:gEGGVQn [举报] No.68812311 管理
>>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.写完就忘了,待会想起来再说
无标题 无名氏 2026-06-09(二)12:17:05 ID:gEGGVQn [举报] No.68812349 管理
>>No.68812311
想起来了,我想的是,我现在两个content表里面的冗余数据都是为了manticore能直接从这一个表导入设计的,但是现在越来越冗余,我在想还值不值得,还是说之后用JOIN导入,现在就不要设计这么冗余了?

UP主: