【问题标题】:Performance of recursive stored procedures in MYSQL to get hierarchical dataMYSQL中递归存储过程获取分层数据的性能
【发布时间】:2010-07-23 21:23:38
【问题描述】:

我有像这样的表员工,
员工 ( emp_id int 主键, emp_name varchar(50), mngr_id int)

这里的 mngr_id 要么为空,要么包含有效的 emp_id。这样就形成了组织中员工的层次结构。

为了遍历整个层次结构,我必须编写递归存储过程。 (在 Oracle 中,使用 CONNECT BY .. START WITH 很容易)

所以问题是,考虑到层次结构的级别不会超过 10 级,这种存储过程对性能的影响是什么!

还有其他方法可以达到同样的效果吗?

【问题讨论】:

    标签: mysql


    【解决方案1】:

    一个相当简单的迭代邻接列表数据库服务器端解决方案:http://pastie.org/1056977

    delimiter ;
    
    drop procedure if exists employee_hier;
    
    delimiter #
    
    create procedure employee_hier
    (
    in p_emp_id smallint unsigned
    )
    begin
    
    declare p_done tinyint unsigned default(0);
    declare p_depth smallint unsigned default(0);
    
    create temporary table hier(
     boss_id smallint unsigned, 
     emp_id smallint unsigned, 
     depth smallint unsigned
    )engine = memory;
    
    insert into hier values (null, p_emp_id, p_depth);
    
    /* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
    
    create temporary table emps engine=memory select * from hier;
    
    while p_done <> 1 do
    
        if exists( select 1 from employee e inner join hier on e.boss_id = hier.emp_id and hier.depth = p_depth) then
    
            insert into hier select e.boss_id, e.emp_id, p_depth + 1 
                from employee e inner join emps on e.boss_id = emps.emp_id and emps.depth = p_depth;
    
            set p_depth = p_depth + 1;          
    
            truncate table emps;
            insert into emps select * from hier where depth = p_depth;
    
        else
            set p_done = 1;
        end if;
    
    end while;
    
    select 
     e.emp_id,
     e.name as emp_name,
     b.emp_id as boss_emp_id,
     b.name as boss_name,
     hier.depth
    from 
     hier
    inner join employee e on hier.emp_id = e.emp_id
    inner join employee b on hier.boss_id = b.emp_id;
    
    drop temporary table if exists hier;
    drop temporary table if exists emps;
    
    end #
    
    delimiter ;
    
    
    call employee_hier(1);
    call employee_hier(3);
    

    【讨论】:

      【解决方案2】:

      关于最后一个问题:"What is the most efficient/elegant way to parse a flat table into a tree?" 有几个不错的选择

      您还应该考虑将递归结果缓存在中间表中。如果您仅在更新层次结构表时更改它,则递归性能影响可以忽略不计。

      编辑: 就我个人而言,我会在我的应用程序的表示层中进行递归,例如在 Web 服务器上。与可以在 SQL 中实现的功能相比,这提供了更大的灵活性,并且您还可以使用会话或应用程序级别的缓存。 (不过,使用通过触发器保持最新的预先构建的数据库表永远不会给您留下过时的缓存。)

      【讨论】:

        【解决方案3】:

        Tomalak:“......我会在我的应用程序的表示层中进行递归......”

        这意味着每次递归发生时,都会从表示层向数据库服务器发送另一个调用。那会非常慢。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-22
          • 2013-11-13
          • 2015-05-20
          • 2015-08-08
          • 2011-03-27
          • 2011-04-14
          相关资源
          最近更新 更多