我在我的网络应用程序上使用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
但是当我使用这种方法时,它会有数百万的数据与该表。这是低效的。
我的问题是有任何有效的方法来做到这一点。我的表结构有什么问题阻止我有效地进行这种查询。
答案 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,
免责声明:我现在只是为自己进行研究。我还没有从任何这些解决方案中获得经验的好处。