首页   注册   登录
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
拉勾
V2EX  ›  MySQL

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

  •  
  •   opengps · 314 天前 · 1819 次点击
    这是一个创建于 314 天前的主题,其中的信息可能已经有所发展或是发生改变。

        以前单位比较依赖 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
        1
    Mazexal   314 天前
    创建了索引没....一个查询 7 秒多怎么想都觉得太可怕了吧....
        2
    opengps   314 天前
    @Mazexal 我给级联字段加了索引之后 7 秒,慢主要是因为数据多,还重复关联导致的,页面没有分页,因为业务上最大顶级用户也不会有太多行结果
        3
    ykrl089   314 天前
    你这个感觉有点像是传销啊……
        4
    h1367500190   314 天前   ♥ 1
    了解下嵌套集合模型(Nested set model)?
        5
    opengps   314 天前
    @ykrl089 确实像,每个顶级用户拉不了多少下级。。。但是顶级用户数量会比较快的增长
        6
    justfindu   314 天前
    可以改表不, 改成用 depth, lft, rgt 来标记级联. 一次性修改全表,增加这些字段. 之后查询就是一个语句
        7
    RubyJack   314 天前   ♥ 1
    冗余第一级,这样查询的时候,只要通过第一级就可以查出全部 5 级的数据,之后业务代码里拼装成级联的即可
        8
    opengps   314 天前
    @justfindu depth 这个办法不错,至少大幅减小了关联时候临时数据集大小,我试试。lft, rgt 我怎么用合适?类似 depth 他原来有个当前第几级的标识列,这个需求只有父级差子级,我是不是用不到?
        9
    opengps   314 天前
    @RubyJack 不是太明白,可否稍微详细指点下
        10
    Troevil   314 天前
    一般有固定级联的都是空间换时间, 冗余数据
        11
    justfindu   314 天前   ♥ 1
    @opengps 搜一下 "无限级联" , 方案就是那个.
        12
    justfindu   314 天前   ♥ 1
    @justfindu "无限级分类"
        13
    justfindu   314 天前   ♥ 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 ,查出所有的子级
        14
    l00t   314 天前   ♥ 1
    如果是 Oracle 数据库的话,类似需求我一般使用层级查询,也就是 start with.... connect by.... 那套。
    使用这个方案需要在表内加一个字段注明某条记录的上一级是谁。

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

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


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

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

    http://www.cnblogs.com/alex2moro/archive/2013/01/03/2842637.html
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3115 人在线   最高记录 4385   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 16ms · UTC 01:07 · PVG 09:07 · LAX 18:07 · JFK 21:07
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1