请教个数据库问题, 5 层固定级联,有啥最好方案查询? - V2EX
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
opengps
0.01D
V2EX    MySQL

请教个数据库问题, 5 层固定级联,有啥最好方案查询?

  •  
  •   opengps
    null 2018-05-14 09:11:33 +08:00 4785 次点击
    这是一个创建于 2738 天前的主题,其中的信息可能已经有所发展或是发生改变。

    以前单位比较依赖 DBA,高级点的数据库优化可以交给 dba 出方案,基本不用开发考虑,现在换了工作接手维护一个项目,不是个技术型公司,需要开发“全能”型。

    涉及 3 个表,其中有个表同时存在级联逻辑。页面查询要求同时展示所有子级信息。
    比如顶级用户 1,列表页需要同时展示,2,3,4,5 级。 二级用户 2,列表需要查询 3,4,5 级,,,,

    我看了下,上一个开发留的方案是,数据库视图,除了基础 2 张表+级联表做了基础数据之外,重复关联 5 次级联逻辑的表,对外表现成了 8 张表做内连接,查询顶级用户 1,耗时 7 秒

    我的方案是去掉后 5 张表的关联,变为 2s,然后前台二次查询单独实现级联数据,但是老员工对于这个改造的工作量不太满意(不知道是不是懒)。

    各位走过路过支个招,还有啥别的方案改动少可以满足提速需求?

    16 条回复    2018-05-15 00:17:20 +08:00
    Mazexal
        1
    Mazexal  
       2018-05-14 09:19:30 +08:00
    创建了索引没....一个查询 7 秒多怎么想都觉得太可怕了吧....
    opengps
        2
    opengps  
    OP
       2018-05-14 09:21:07 +08:00
    @Mazexal 我给级联字段加了索引之后 7 秒,慢主要是因为数据多,还重复关联导致的,页面没有分页,因为业务上最大顶级用户也不会有太多行结果
    ykrl089
        3
    ykrl089  
       2018-05-14 09:23:17 +08:00
    你这个感觉有点像是传销啊……
    h1367500190
        4
    h1367500190  
       2018-05-14 09:23:50 +08:00   1
    了解下嵌套集合模型(Nested set model)?
    opengps
        5
    opengps  
    OP
       2018-05-14 09:24:23 +08:00
    @ykrl089 确实像,每个顶级用户拉不了多少下级。。。但是顶级用户数量会比较快的增长
    justfindu
        6
    justfindu  
       2018-05-14 09:27:03 +08:00
    可以改表不, 改成用 depth, lft, rgt 来标记级联. 一次性修改全表,增加这些字段. 之后查询就是一个语句
    RubyJack
        7
    RubyJack  
       2018-05-14 09:31:37 +08:00   1
    冗余第一级,这样查询的时候,只要通过第一级就可以查出全部 5 级的数据,之后业务代码里拼装成级联的即可
    opengps
        8
    opengps  
    OP
       2018-05-14 09:32:18 +08:00
    @justfindu depth 这个办法不错,至少大幅减小了关联时候临时数据集大小,我试试。lft, rgt 我怎么用合适?类似 depth 他原来有个当前第几级的标识列,这个需求只有父级差子级,我是不是用不到?
    opengps
        9
    opengps  
    OP
       2018-05-14 09:33:56 +08:00
    @RubyJack 不是太明白,可否稍微详细指点下
    Troevil
        10
    Troevil  
       2018-05-14 09:34:28 +08:00
    一般有固定级联的都是空间换时间, 冗余数据
    justfindu
        11
    justfindu  
       2018-05-14 09:34:58 +08:00   1
    @opengps 搜一下 "无限级联" , 方案就是那个.
    justfindu
        12
    justfindu  
       2018-05-14 09:36:40 +08:00   1
    @justfindu "无限级分类"
    justfindu
        13
    justfindu  
       2018-05-14 09:42:18 +08:00   2
    @opengps 其实就是一个树型的结构. 父级 的左标记 lft 为起点, 然后所有子级都有各自的左节点和右节点基数. 最后回到到父级的右标记 rgt 计数.
    类似 A 有 B C D, B 有 E F,
    那么
    A.lft = 1 ,
    B.lft = 2 ,
    E.lft=3, E.rgt =4, F.lft = 5, F.rgt = 6, B.rgt = 7, C.lft=8 ,C.rgt = 9, D.lft=10, D.rgt=11, A.rgt=12,

    然后 A.depth = 0 , B C D depth = 1, E F depth = 2,

    这样可以通过 查询 lft > A.lft 并且 rgt < A.rgt ,查出所有的子级
    l00t
        14
    l00t  
       2018-05-14 09:52:44 +08:00   1
    如果是 Oracle 数据库的话,类似需求我一般使用层级查询,也就是 start with.... connect by.... 那套。
    使用这个方案需要在表内加一个字段注明某条记录的上一级是谁。

    但是具体到你的情况,还得看 数据量, 表结构,以及现有查询方案的表现来决定优化方案。你啥都没贴,那就没啥可帮的了……
    corningsun
        15
    corningsun  
       2018-05-14 18:08:59 +08:00   1
    可以试下减少数据库查询次数,优点是不需要修改现在的表结构。

    查第一层 得到 所有的 level_1_ids
    再根据 level_1_ids 去查第二层 level_2_ids
    基本只需要查询很少的次数,然后基本都是内存操作了,只要内存够,性能 应该没啥问题。


    Java 的 stream 操作,做这些事情还是挺顺手的。。

    当然由于非常依赖内存和 cpu,数据量到底有多大,还需要考虑实际情况。
    fuxkcsdn
        16
    fuxkcsdn  
       2018-05-15 00:17:20 +08:00 via iPhone
    可以参考下这方案(和 13 楼说的应该是同一方案)

    http://www.cnblogs.com/alex2moro/archive/2013/01/03/2842637.html
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3852 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 36ms UTC 00:53 PVG 08:53 LAX 16:53 JFK 19:53
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86