递归这种情况下的最优解?
Recursion the optimal solution in this case?
这让我很头疼。我正在构建一个系统,可以处理许多项目、组和文件引用。
请看看这个:
用户应该能够创建无限数量的项目、无限数量的组并附加无限数量的文件引用——就像普通的 PC 文件结构处理驱动器号、文件夹和文件一样。
所有提到的元素都驻留在 MySQL 数据库中。但是,我不确定这(见下文)是否是构建整个事物的最佳方式:
如您所见,它包含一个名为 "Xrefs" 的实体,包含项目和组。行指向自身内部,这可能使其成为检索数据时进行递归调用的理想选择。
一种不同的方法可能是为项目创建 1 个实体,为组创建 1 个实体,为文件引用创建 1 个实体...以及 1 个辅助实体,它将三个实体联系在一起,还包含 "parent" 值,(类似于第一个解决方案)引用上层元组以创建层次结构。
如果你要构建一个类似的项目,你会怎么做?
您的结构很好 - 因为您正在构建树,而不是一般图,所以不需要单独的 table 将实体联系在一起。我会将项目放入它们自己的 table,因为它们似乎独立存在,除非您还必须支持项目之间的层次结构。
但是,鉴于您的 RDBMS 是 MySQL,您在构建递归查询时会遇到问题。例如,尝试考虑一个查询,它会为您提供与 1
的 xfer_id
相关的所有文件(即项目)。 None 的文件与该 ID 相关联,因此您需要找到您的第一级组,然后是您的第二级组,然后将文件绑定到它们。由于您的组可以嵌套在任意数量的级别中,因此您的查询也必须是递归的。
虽然你一定可以做到,it is currently not simple, and requires writing stored procedures。对于这种情况,一种常见的方法是在 RDBMS 的帮助下在内存中构建树。诀窍是在每个组中存储顶级项目的id
,即
xfer_id xfer_fk xfer_top
------- ------- --------
1 - 1
2 1 1
3 1 1
4 3 1
5 3 1
现在,带有条件 WHERE xfer_top=...
的查询将为您提供所有个体 "parts",它们可以在内存中组合,而无需将整个 table 放入内存。
您遇到了 MySQL 最著名的限制之一:使用所谓的递归查询 (PostgreSQL) 或 CTE 查询 (Oracle) 的能力。有一些可能的解决方法,但考虑到具有此类要求的项目,您可能会因许多其他众所周知的 MySQL 限制而遭受很多痛苦。在这个问题上,即使是 SQLLite 也会更有用(除了一个并发用户限制)。
DBIx::Class 有一些组件可以帮助您规避此 MySQL 限制,搜索 Nested Trees、Ordered Trees ,带递归查询…[DBIx::Class::Tree::NestedSet][1]
您将需要对以下内容的支持:7.8. WITH Queries (Common Table Expressions),MySQL 不会为您提供。
这让我很头疼。我正在构建一个系统,可以处理许多项目、组和文件引用。
请看看这个:
用户应该能够创建无限数量的项目、无限数量的组并附加无限数量的文件引用——就像普通的 PC 文件结构处理驱动器号、文件夹和文件一样。
所有提到的元素都驻留在 MySQL 数据库中。但是,我不确定这(见下文)是否是构建整个事物的最佳方式:
如您所见,它包含一个名为 "Xrefs" 的实体,包含项目和组。行指向自身内部,这可能使其成为检索数据时进行递归调用的理想选择。
一种不同的方法可能是为项目创建 1 个实体,为组创建 1 个实体,为文件引用创建 1 个实体...以及 1 个辅助实体,它将三个实体联系在一起,还包含 "parent" 值,(类似于第一个解决方案)引用上层元组以创建层次结构。
如果你要构建一个类似的项目,你会怎么做?
您的结构很好 - 因为您正在构建树,而不是一般图,所以不需要单独的 table 将实体联系在一起。我会将项目放入它们自己的 table,因为它们似乎独立存在,除非您还必须支持项目之间的层次结构。
但是,鉴于您的 RDBMS 是 MySQL,您在构建递归查询时会遇到问题。例如,尝试考虑一个查询,它会为您提供与 1
的 xfer_id
相关的所有文件(即项目)。 None 的文件与该 ID 相关联,因此您需要找到您的第一级组,然后是您的第二级组,然后将文件绑定到它们。由于您的组可以嵌套在任意数量的级别中,因此您的查询也必须是递归的。
虽然你一定可以做到,it is currently not simple, and requires writing stored procedures。对于这种情况,一种常见的方法是在 RDBMS 的帮助下在内存中构建树。诀窍是在每个组中存储顶级项目的id
,即
xfer_id xfer_fk xfer_top
------- ------- --------
1 - 1
2 1 1
3 1 1
4 3 1
5 3 1
现在,带有条件 WHERE xfer_top=...
的查询将为您提供所有个体 "parts",它们可以在内存中组合,而无需将整个 table 放入内存。
您遇到了 MySQL 最著名的限制之一:使用所谓的递归查询 (PostgreSQL) 或 CTE 查询 (Oracle) 的能力。有一些可能的解决方法,但考虑到具有此类要求的项目,您可能会因许多其他众所周知的 MySQL 限制而遭受很多痛苦。在这个问题上,即使是 SQLLite 也会更有用(除了一个并发用户限制)。
DBIx::Class 有一些组件可以帮助您规避此 MySQL 限制,搜索 Nested Trees、Ordered Trees ,带递归查询…[DBIx::Class::Tree::NestedSet][1]
您将需要对以下内容的支持:7.8. WITH Queries (Common Table Expressions),MySQL 不会为您提供。