具有Laravel关系的MySQL嵌套集模型

时间:2014-09-30 20:37:09

标签: php mysql performance nested-set-model

晚上好!

我正在开发一个允许Laravel基于MySQL嵌套集模型(lft和rgt键)建立关系的软件包。

图例:X,Y,Z,A,B,C是整数。

我们假设我们想在eshop类别中使用它。

我的第一个任务是创建关系。我已设法创建一个查找当前类别的父级的关系。我的查询如下:

select * from categories where lft < X and rgt > Y order by lft limit 1

这完全正确。但是,当我想加载时会出现问题,比方说,100个类别。然后,它是100个类别的一个SQL查询:

select * from categories limit 100

和每个类别的父级的一个SQL查询:

select * from categories where lft < X and rgt > Y order by lft desc limit 1

总共 101 sql查询。

这是问题部分的来源。我想使用一种名为Eager Loading的技术(将所有关系查询合并到一个查询中)。但是怎么做呢?

解决方案否。 1

我的第一个解决方案是收集所有lft和rgt键:

select * from categories limit 100

并创建如下所示的查询:

select * from categories where (lft < X or lft < Y or lft < Z ...)
and ( rgt > A or rgt > B or rgt > C ...) order by lft desc

但是,这个解决方案根本不起作用。它返回所有类别的父母。

解决方案否。 2

然后,我尝试使用此方法使其正常工作。原始查询看起来是一样的。

select * from categories limit 100

但加载父母是完全不同的:

(select * from categories where lft < X and rgt > Y order by lft desc limit 1)
union all 
(select * from categories where lft < A and rgt > B order by lft desc limit 1)
union all...

此查询仅返回相关结果,这是完美的,但是要向其子项添加父项,我必须运行(在PHP端)foreach循环通过原始查询的所有结果(从类别限制中选择*) 100)并且在foreach内部我必须运行另一个迭代每个父项(来自原始查询)和第二个foreach内部,有一个比较逻辑,它使得10 000(100 * 100)个周期加上比较= looooooooooooong执行

解决方案否。 3

所以我想到了另一个解决方案,这在我看来是最好的。这只是对第二种解决方案的改进。

原始查询:

select * from categories limit 100

关系查询:

(select categories.*, X as child_lft, Y as child_rgt from categories
where lft < X and rgt > Y order by lft desc limit 1)
union all
(select categories.*, A as child_lft, B as child_rgt from categories
where lft < A and rgt > B order by lft desc limit 1)
union all...

所以,现在,在PHP方面,我有一个包含原始查询结果的数组(100个项目)和一个包含关系查询结果的数组(100个项目)。改进之处在于,现在,每个父结果都包含请求它的类别的lft和rgt键(child_lft和child_rgt)。现在,PHP脚本要快得多。首先,我创建一个包含所有父项的新数组(让它命名为$ parents),每个项目键($ parents中值的键)是代码(child_lft.child_rgt =&gt; 1.5),用于标识类别请求它。这是一个循环100次的foreach。第二个foreach遍历原始查询的结果,并检查$ parents数组是否包含一个值,该值包含适合其lft和rgt键的键。所以另外100次迭代。总计,200次迭代=完美!但是关系查询&#39;没有我想要的那么快。

那么,还有另一种方法吗?或者有没有办法如何在解决方案中进行我的SQL查询。 3更快?

感谢您阅读它。谢谢!

1 个答案:

答案 0 :(得分:1)

您可以使用Baum来解决您在Laravel中尝试做的事情,并且涵盖了大部分角落案例。