V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
mebtte
V2EX  ›  MySQL

mysql 保存族谱应该怎么设计?

  •  1
     
  •   mebtte ·
    mebtte · 2020-05-12 18:05:52 +08:00 · 7122 次点击
    这是一个创建于 1436 天前的主题,其中的信息可能已经有所发展或是发生改变。
    58 条回复    2020-05-14 09:17:02 +08:00
    l1nyanm1ng
        1
    l1nyanm1ng  
       2020-05-12 18:07:59 +08:00   ❤️ 1
    百度 ❌
    谷歌 ❌
    打开 V2EX 来和问问题(实则借机开始划水 ✔️
    wangkun025
        2
    wangkun025  
       2020-05-12 18:11:16 +08:00
    people
    relationships
    person_relationships
    mebtte
        3
    mebtte  
    OP
       2020-05-12 18:11:35 +08:00
    @l1nyanm1ng 猜对了
    mebtte
        4
    mebtte  
    OP
       2020-05-12 18:12:31 +08:00
    @wangkun025 要支持正反向查询, 比如爷爷的孙子们 /孙子的爷爷
    xupefei
        5
    xupefei  
       2020-05-12 18:14:36 +08:00 via iPhone   ❤️ 1
    你需要的应该是 RDF 。
    annielong
        6
    annielong  
       2020-05-12 18:14:54 +08:00
    基本的都是递归,id,name,upid
    2exploring
        7
    2exploring  
       2020-05-12 18:16:27 +08:00
    一张人表,一张父子关系表,不就结了
    wangkun025
        8
    wangkun025  
       2020-05-12 18:17:22 +08:00   ❤️ 1
    @mebtte 加需求要加钱的
    superrichman
        9
    superrichman  
       2020-05-12 18:21:33 +08:00 via iPhone
    可以参考《 sql antipatterns 》这本书第三章来设计存储和读取树形结构。
    mebtte
        10
    mebtte  
    OP
       2020-05-12 18:29:21 +08:00
    @2exploring 隔了好几代不好查询
    yangliulnn
        11
    yangliulnn  
       2020-05-12 18:47:04 +08:00 via Android
    左右值了解一下
    egfegdfr
        12
    egfegdfr  
       2020-05-12 19:01:22 +08:00
    在 id,name,upid 的基础上在加一个 path 的字段、用来记录这个当前节点的所有父节点。
    hantsy
        13
    hantsy  
       2020-05-12 19:03:11 +08:00
    这样 100%用 Neo4j 方便啦。
    hteen
        14
    hteen  
       2020-05-12 19:03:15 +08:00 via iPhone
    闭包表
    FFFire
        15
    FFFire  
       2020-05-12 20:20:31 +08:00
    建议使用 Excel
    k9990009
        16
    k9990009  
       2020-05-13 00:07:44 +08:00 via Android
    不就是树嘛,除了父 ID,再加上父路径 1,3,5,…… 想怎么查都阔以
    Keyes
        17
    Keyes  
       2020-05-13 00:11:35 +08:00 via iPhone
    爸爸辈太多的话,查孙子会比较吃性能,我只想到了买个更好硬件的 server

    然后:图数据库就干这个事的
    izoabr
        18
    izoabr  
       2020-05-13 00:16:57 +08:00
    我觉得 JSON 也挺合适的,有结构且明文
    Solarest
        19
    Solarest  
       2020-05-13 00:51:40 +08:00 via Android
    参考图数据库的设计方式,分表存:实体 a 、实体 a 和 b 的关系、实体 b 。
    tulongtou
        20
    tulongtou  
       2020-05-13 01:55:38 +08:00 via iPhone   ❤️ 3
    感觉不用设计想怎么存怎嘛存,族谱能有多少人?几百几千?哪怕上万了,也不需要设计啊,这个数量级怎么存都没毛病
    ericgui
        21
    ericgui  
       2020-05-13 02:19:55 +08:00
    族谱就是一个 tree
    你考虑一下
    lights
        22
    lights  
       2020-05-13 02:43:14 +08:00
    如果频繁间隔很多代际查询的话,建议上图数据库,不推荐 OrientDB (我被它坑得死去活来)
    可以考虑 Mysql 层面模仿图数据库的存储结构(如 19 楼所说)

    另外因为“关系数据”内容量很小(甚至不会超过 50MB ),可以每次将关系数据从 Mysql 中缓存到内存,然后每次查询直接在内存中用图算法算,再将获取到的关系结果到 MySQL 中查询具体的数据(有现成的图查询库可以找找看)
    lumotian
        23
    lumotian  
       2020-05-13 04:46:17 +08:00
    mongodb
    levelworm
        24
    levelworm  
       2020-05-13 06:25:39 +08:00 via Android
    最高多少代,直接所有数据 dump 出来存储。。。
    ebony0319
        25
    ebony0319  
       2020-05-13 08:31:50 +08:00 via Android
    多一列:祖先是谁。这样方便认祖归宗(查并集)。比如第五代与十五代,只要祖宗相同说明是同族。
    fxxwor99LVHTing
        26
    fxxwor99LVHTing  
       2020-05-13 08:52:05 +08:00
    如果数据量不大,那么直接就一棵树就行,
    表结构,一张表也行吧,
    id,parentId
    查询的时候一次性把同族的所有数据拿出来,然后根据 parentId 把各个节点链接成一棵树,同时把节点在 map 里面根据 id 存一份,这样查询就很快了,
    entity 里面两个属性 parentNode, 和 childrenNodes,父节点只有一个,但是子节点可能有多个
    wei193
        27
    wei193  
       2020-05-13 08:56:53 +08:00 via Android
    用两个字段,一个字段记录代数,一个字段记录关系树,比如 1/2/4/8 。那么你可以用 Like 1/2/% AND 4 代 来找他的孙子。当年我是这样做的,有更多需要可以啊。
    wei193
        28
    wei193  
       2020-05-13 09:02:38 +08:00 via Android
    @wei193 有完整的设计,包括直接生成电子书,自定义字体这一些。😂😂😂
    tankren
        29
    tankren  
       2020-05-13 09:05:14 +08:00
    纸质版的族谱看起来才有意思
    encro
        30
    encro  
       2020-05-13 09:19:00 +08:00
    非常有意思的题目,
    昨天想了很久,
    觉得没有很好答案。

    今天忽然想到的:
    族谱有一个特点就是写入少,
    所以可以建立一个缓存表,
    缓存关系链。

    比如:

    people 表:
    id,
    name,
    father_id,
    mother_id,
    order,

    relation 表:
    id,
    from_id,
    to_id,
    type


    这里 people 是常规的做法就好,
    people 新增和修改的时候,维护好 relation 表上下的关系。
    这样查询的时候自动根据 relation 以及 type 就能一次查到所有关联关系。
    12tall
        31
    12tall  
       2020-05-13 09:19:33 +08:00
    数据部太多的话,有一种想法,数据表结构
    id, name, p_id
    然后将查询结果保存到哈希表常驻内存,也可以再构造一个树,个人觉得比较适合不常变的数据

    反模式里面的闭包表也用过,就是一个自己关于自己的中间表,增删改时会相对复杂些,如果存很多份族谱的,这种应该比较合适
    encro
        32
    encro  
       2020-05-13 09:24:13 +08:00
    people 表可以扩展一下:
    id,
    family_id, // 族号
    name,
    father_id,
    mother_id,
    order, // 第几个孩子
    level, // 第几代


    relation 表也可以扩展下:
    id,
    from_id,
    to_id,
    type,
    level, // 相对层级 可以为负数
    xuanbg
        33
    xuanbg  
       2020-05-13 09:25:42 +08:00
    数据结构好说,麻烦的是关系。假设曹丞相收了吕布女儿为妾,吕布认曹丞相为父……

    你说这曹氏族谱该怎么写
    dog82
        34
    dog82  
       2020-05-13 09:30:49 +08:00
    简单的就 id parent_id 递归查询就行,mysql postgre oracle 都行
    encro
        35
    encro  
       2020-05-13 09:32:04 +08:00
    @wangkun025

    才发现 2 楼就有利用关系表的意思了,不过当时没有看清楚。

    前面有说到用 path 的办法,如果层级不多是可以的,层级多了,索引太长吧,如果真追溯到祖宗 5 代以上。

    其实前期数据不多,可以不要 relation 表,有 family_id,level 就可以了,根据 family_id 和 level 就可以查出上下几代的数据,用程序运算也很快的。
    encro
        36
    encro  
       2020-05-13 09:33:44 +08:00
    @xuanbg

    笑死了。。
    gamexg
        37
    gamexg  
       2020-05-13 09:34:54 +08:00
    我想起了一个族谱软件作者的吐槽

    客户反馈族谱软件挂了,作者检查后发现,爸爸的妻子是女儿(记不清了,类似的关系),死循环了。

    不知道你这里是否需要考虑这种少见的关系。
    laminux29
        38
    laminux29  
       2020-05-13 09:36:41 +08:00
    论各种数据结构如何转化为数据库的表与关系。
    encro
        39
    encro  
       2020-05-13 09:37:27 +08:00   ❤️ 1
    create index family_level(family_id,level);

    select * from people where family_id=3 and level between current_level-3,current_level+3;

    这样高性能将上下三代查出来了。

    这样看来不要 relation 表也是可以的。
    hbolive
        40
    hbolive  
       2020-05-13 09:37:43 +08:00
    @tankren 产品经理:让设计加下班,你们后端也要考虑下,让电脑和手机上看起来都要有纸质版的感觉。。
    ylsc633
        41
    ylsc633  
       2020-05-13 10:13:20 +08:00
    我也考虑过 做一个族谱! 因为我爸正在把 老祖宗传下来的族谱进行 图形化!

    我再配合一个网站 就完美了!

    族谱除了简单的 树形结构!

    其实还有 其他的情况! 比如 某某 过继 给 某某! 那么他就会有两个父级! 甚至多个! 这种情况在族谱里经常出现!

    还是这种情况 年轻时过继给某某! 去世后 迁回, 还属于出生的那一支....


    另外 图形化的 我参考过 那个 全历史 感觉不错! 可惜不会写
    tankren
        42
    tankren  
       2020-05-13 10:24:26 +08:00
    @hbolive 哈哈 展示不是前端的活吗
    hcymk2
        43
    hcymk2  
       2020-05-13 10:24:42 +08:00
    软件真的好难做啊 coolshell.cn/articles/4811.html
    kiracyan
        44
    kiracyan  
       2020-05-13 10:33:12 +08:00
    @ylsc633 这个过继的关系可以区分关系类型吧 比如首先考虑直系血亲 然后过继 领养等其他的关系可以区分开来
    x66
        45
    x66  
       2020-05-13 10:56:04 +08:00
    左右值
    legiorange
        46
    legiorange  
       2020-05-13 12:36:17 +08:00
    @ylsc633 考虑过,这个时候关系本身的冗余设计体现了真正的用途。和 44 楼说的一样,但维持原来的父关系是必要的(溯源),再增加一个关联关系字段似乎是稳妥的方案。
    比如 两个父,一个母,异父同母的孩子 X2,看似就可以妥善的解决了?
    Baelish725
        47
    Baelish725  
       2020-05-13 12:46:20 +08:00
    这种用图数据库比较方便,不用考虑设计复杂的数据结构,图数据库就是为了解决这种社交关系、环状、树状的关系设计的
    00chang
        48
    00chang  
       2020-05-13 13:51:28 +08:00
    @hcymk2 我的软件没有 bug,是你的生活有 bug 手动狗头
    justfindu
        49
    justfindu  
       2020-05-13 13:52:14 +08:00
    左右值树形结构就行了
    starcraft
        50
    starcraft  
       2020-05-13 14:27:13 +08:00
    邻接表就行。别去存什么完整路径,顶多加个 level,数据少的可怜的话,连这个都不用,反正直接递归就完事了。注意个环检测。尽管 mysql 是 8 加入的 cte,但老版本也能自己模拟,就是性能肯定比不上原生支持。
    aguesuka
        51
    aguesuka  
       2020-05-13 17:29:03 +08:00 via Android
    @encro close table
    guolaopi
        52
    guolaopi  
       2020-05-13 17:55:19 +08:00
    @encro #39
    使用 level 真的很巧妙,这样的话要找任何一代的上下 X 代,就从他的 level +- X 即可。
    太棒了思路!
    我还在想怎么找爷爷的爷爷辈,这样只要找到爷爷的 id,然后 level+3 即可,无需递归。

    但是存在一个缺陷,祖先元素( root )发生变化后所有的 level 是不是都要变化?

    假设现在祖先是 A,最顶级的元素,按这个设计 A 的 level 应该是 0 。
    假若通过别的某些途径证明 A 上面还有 AAA 是 A 的父级,那么此时 AAA 就应该是族谱里的祖先,
    如果是这样的话 level 应该怎么搞,-1 吗?
    encro
        53
    encro  
       2020-05-13 18:48:37 +08:00
    结合大家说的变更问题,那么需要将关系抽离出来:


    people 表:
    id
    name 姓名


    relation 表:
    id
    family_id 族号 一个用户可能存在多个族谱中,比如外嫁后进入其他族谱
    people_id 用户编号
    level 代系
    relate_people_id 关联人,
    type 关系:如丈夫,妻子,儿子,孙子,情人
    order 第几个孩子,第几任妻子


    alter table relation create index family_level(family_id,level);

    select * from relation where family_id=3 and level between current_level-3,current_level+3;

    这样高性能将上下三代查出来了。

    这两个表记录基本不用改(除非录错了),任何时候都是增加记录即可,所以维护也非常简单。

    界面展示上,查询出上下几代,然后名字作为主要展示标签,关系用连线展示,关系和人是多对多,完美解决关系混乱的问题。

    这里一个人可能即是二代也是三代,是两个身份,所以算两个点。

    不知道怎么 v2 贴图,参考图我先放我自己 blog 上了。

    族谱的数据设计 https://c4ys.com/archives/2141
    encro
        54
    encro  
       2020-05-13 18:51:07 +08:00
    @guolaopi

    如果新增加了超祖辈,子代数都+1 。
    encro
        55
    encro  
       2020-05-13 18:54:09 +08:00
    level 代表是族谱里面的第几代。
    如果发现了新的祖先,然么当然自己代数要加一。
    比如李渊原来 level 是 1 代,然后认了老子做祖宗,那么他就不 1 代了,老子是 1 代。
    Zien
        56
    Zien  
       2020-05-13 19:10:51 +08:00 via Android
    parent_id 和 person_id 级联(假定只是父系族谱
    realpg
        57
    realpg  
       2020-05-14 00:25:44 +08:00
    族谱这种除非录入错误,不会 update 的数据库
    基础表按 relation 结构
    然后针对热度超高冗余度就好了……
    反正你族谱再大也不会超过十万人吧
    在数据库这都是小 case

    别说爷爷,把四五代数据都生成冗余类视图的表都没啥事儿
    12tall
        58
    12tall  
       2020-05-14 09:17:02 +08:00
    @xuanbg 让我想到了,错综复杂部门领导关系~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5722 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 01:44 · PVG 09:44 · LAX 18:44 · JFK 21:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.