@
simonlu9 > 主键如果设那么长考虑插入时候分裂情况
我 3 楼的设计,直接按照『最差情况』,全部『随机插入』,叶节点『全裂成一半』考虑的
> 允许用户( at_user_id )最好是建另外一个表,字符串查找不建议
我打完下面这堆,才看到你的回复。最后计算,也大体验证你所说,『单独表』更可能比『字符串查找』快
如果是我 8 楼所认为的那样设计,那么:
唯一索引『主键「权限类型,作者 ID 」,动态 ID 』,叶节点每行记录 14 字节。
随机插入情况下,一个叶节点一半空间可用,可存约 585 行。
再拿 3 楼的 3W 条动态+1W 条<指定><他人 ID>可见动态(这对 3 楼的设计无影响,且合情合理),计算下硬盘 IO:
1. 花 1 ~ 2 次 IO ,查询其他表,来确定 <他人和自己是好友>
2. 查询 <公开>、<朋友可见> 每种类型的前 585 条记录,各花费 1 ~ 2 次 IO 。往后每 585 条,再花费 1 次 IO 。
3. 查询 <指定> 类型,和第 2 步类似,但还要确定自己是否在权限内:
3.1 「允许用户 IDs 」 JSON
每条动态,都要花 1 ~ 2 次 IO (偏向 2 ~ 3 次,此表很容易变深)回『动态表』,获取「允许用户 IDs 」,然后 find_in_set 或 json 函数确定。
假设『动态表』每行记录 0.5KB (不大吧),顺序插入情况下,叶子节点预留 1/16 空间,每个叶子节点可存 30 行
运气好,用户连发 30 条动态,全在一个叶子节点里,能命中缓存 29 次。运气差,无法命中缓存
3.2 『用户动态指定可见表』
每条动态,都要花 1 ~ 2 次 IO ,exists
此表叶节点每行记录 26 字节,随机插入情况下,一半空间可用,可存约 315 行。
运气好,用户连发 315 条动态,且每条动态都只指定一人可见,则可全在一个叶节点里。反之分散各处,无法命中缓存
final. 总计:1~2 + 2 * (1~2 + ceil(10000 / 585)) + (1~2 + ceil(20000 / 585) + …) = 75 ~ 79 + …
若用 3.1:75~79 + (ceil(20000 / 30) ~ 20000) * 1~2 = 742 ~ 40079 次 IO
若用 3.2:75~79 + (ceil(20000 / 315) ~ 20000) * 1~2 = 139 ~ 40079 次 IO
如果固态 16KB IOPS 有 13W ,那每秒最多可查询 3 ~ 1000 个类似这样的人的所有动态 ID 列表
看起来,是因为每条动态,都要验证权限,导致的回表 /查表次数太多
当然,指定某人可见的动态,应该不会这么多。可以算出个阈值,超过此值这种设计不划算
我 3 楼那样的设计,是将同类动态的行记录(某人公开、某人私有、某人朋友可见、某人指定他人 1 ,某人指定他人 2 ,……),尽可能凑在一起,实现:
1. 能迅速跳过某些类别的所有行记录(如,跳过某人私有、某人指定非自己的其他所有人)
2. 能迅速定位到某一类的第一行
3. 能利用上 B+ 树的叶子节点双向链表的特性,迅速遍历完某一类的余下行
这样的表,用文件系统类比,就是(如下),要啥类别,就直接读那个文件(叶子节点),直接跳过其他所有:
用户动态权限文件夹 /
用户 A/
公开动态 ID 列表.txt
私有….txt
朋友可见….txt
指定可见 /
用户 B 可见….txt
用户 C 可见….txt
用户 B/
……