如何有效地查询有向无环图

时间:2012-06-22 08:43:34

标签: mysql directed-acyclic-graphs

我在我的网络应用程序上使用mysql。应用程序表包含一个supervisor表和一个employee表。员工表包含有关每个员工的信息。主管表包含两列,如下所示。

supervisor_id -> which is employee id of the supervisor
subordinate_id -> which is the employee id of the subordinate. 

每个下属可以有多个主管,一个主管下属可以是其他员工的主管。所以表格记录可以跟随。

supervisor_id | subordinate_id
1             | 2
1             | 3
2             | 4
4             | 5
3             | 6
3             | 4

在上面的示例中,有一个主管链。主管1有2个,3个,4个,5个和6个作为他的下属。主管2有4,5作为下属。而且它也可以为下属提供多个主管。

当我查询主管2的所有下属时,我现在使用如下查询。

public function getSubordinate($id) {
 $query = "SELECT * FROM supervisor WHERE subordinate_id = $id";
 // get results and return
}

所以我现在所做的是首先将id发送为2以获得它的直接下属。然后,对于每个生成的下属,我一次又一次地运行查询以获得完整的下级链。

这对于一小组数据来说没问题。但是这个主管表将有数千个数据,因此我必须进行数千次查询才能找到主管链,并且需要时间才能给出结果。

由于下属可以拥有多个主管,因此嵌套集不会是一个确切的答案。

我也经历过这个解决方案。 http://www.codeproject.com/Articles/22824/A-Model-to-Represent-Directed-Acyclic-Graphs-DAG-o

但是当我使用这种方法时,它会有数百万的数据与该表。这是低效的。

我的问题是有任何有效的方法来做到这一点。我的表结构有什么问题阻止我有效地进行这种查询。

2 个答案:

答案 0 :(得分:0)

你说的是非循环图,所以也许我离开这里 - 但它同时听起来就像你需要一些正常的主管和员工层级?它可以用树结构来完成吗?

我不确定,但听起来你只需要一个树形结构?我认为最简单的方法就是将所有名字存储在一个表中,并使用两个字段来更新人员之间的关系。这些字段是左右的。

                              _______  
                           1 | peter | 20
                              _______
             ______                        ______
          2 | paul | 17                18 | john | 19
             ______                        ______
    _____            _______
 3 |judas | 4      5 | maria | 16
    _____            _______


               _____             ________
            6 |seth  | 7      8 | abraham | 15
               _____             _______

                                ______          
                              9 |bill | 14
                                 _____

                          _____                _______
                      10 |kenny | 11      12 | moses | 13
                          _____                _______

谁是摩西的老板?每个拥有更高权利和爱人的人都会给你比尔,亚伯拉罕,玛丽亚,保罗和彼得:-)这在数据库中根本不需要时间就可以了。如果这很有趣,我可以更新这个答案,详细说明如何执行此操作。

 table  left   right

 peter  1      20
 paul   2      7
 judas  3      4
 maria  5      16
 seth   6      7
 ... etc


 select * from people where left < 12 and right > 13

结果:

 bill     9     14
 abraham  8     15
 maria    4     16
 paul     2     17
 peter    1     20

答案 1 :(得分:0)

所有主要的数据库应用程序(包括MySQL和MariaDB)现在都支持使用公用表表达式的递归查询。这是在MySQL 8.0版和MariaDB 10.2.2版中引入的。 PostgreSQL甚至早就有支持。 Oracle拥有它,SQL Server在2005版本中添加了它。实际上,快速搜索表明Sqlite也支持Common Table Expressions。

因此,您可能正在寻找的答案是使用公用表表达式和递归查询。与“ A Model to Represent Directed Acyclic Graphs (DAG) on SQL Databases”相比,该方法被认为是更好的解决方案的一些原因在这里说明:

关系模型中的编码和查询图
https://drtom.ch/posts/2012/02/11/Encoding_and_Querying_Graphs_in_the_Relational_Model/

(您可以忽略他所说的部分,“它不会特别在不支持CTE的MySQL或sqlite3上运行。”如上所述,情况已不再如此。)

正如您在问题中指出的那样,“当我使用此方法时,该表将具有数百万的数据。”如果您一直在为提高效率而进行空间交换,那么这可能并不算太糟,但是正如汤姆博士的帖子在一个示例中解释的那样:

  

删除或插入红色弧的操作也需要花费θ(n ^ 2)。

对于这些操作,这是n平方的努力;您可以获得查询效率,但以空间效率低下和插入/删除效率低下为代价。他进一步指出

  

实际上,所有大型的现实世界网络都是稀疏的。它们的边比可能的要少得多,即m«n ^ 2。

公平地说,您链接的Kemal Erdogan的Code Project文章是2008年的;那时CTE并不是普遍可用的。此外,埃尔多安(Erdogan)在权衡取舍方面做出了明智的选择,如下所述:

  

我拥有的解决方案基于递归[too]。但是,我不将递归推迟到查询时间,而是在插入时进行递归,假设该图实际上比修改的查询更多(到目前为止,我所遇到的所有情况都是如此)。

如果在阅读了汤姆博士的文章后,您最终更喜欢埃尔多安的权衡,那么您可以通过在此处查看Laravel的实现方式来限制其他效率低下的问题:

GitHub-telkins / laravel-dag-manager:一种基于SQL的Laravel有向无环图(DAG)解决方案。 https://github.com/telkins/laravel-dag-manager

尤其要研究Max Hops,并在自己的解决方案中实现类似的功能。

这在Laravel配置文件中:

/*
|--------------------------------------------------------------------------
| Max Hops
|--------------------------------------------------------------------------
|
| This value represents the maximum number of hops that are allowed where
| hops "[i]ndicates how many vertex hops are necessary for the path; it is
| zero for direct edges".
|
| The more hops that are allowed (and used), then the more DAG edges will
| be created.  This will have an increasing impact on performance, space,
| and memory.  Whether or not it's negligible, noticeable, or impactful
| depends on a variety of factors.
*/

'max_hops' => 5,

免责声明:我现在只是为自己进行研究。我还没有从任何这些解决方案中获得经验的好处。