PHP/MySQL面向对象编程:从SQL中加载复杂对象

8

我正在为一位房地产经纪人开发项目。我在设计中有以下对象/MySQL表:

Complexes
Units
Amenities
Pictures
Links
Documents
Events
Agents

这些是上述对象之间的关系。
Complexes have a single Agent.
Complexes have multiple Units, Amenities, Pictures, Links, Documents, and Events.
Units have multiple Pictures, Links, and Documents.

在数据库中,设施、图片、链接、文档和事件都有必要的外键来指定它们属于哪个单元/复合物。

我需要从数据库中加载必要的对象到PHP中,以便在项目中使用它们。

如果我尝试在一个查询中选择表中的所有数据,使用LEFT JOIN,对于每个唯一的单元,我将得到至少(# of links)*(# of pictures)*(# of documents)行。加上设施和事件,我将得到所有这些*#设施*#事件,对于每个复合体...不确定我是否想尝试将其加载到PHP对象中。

另一种可能性是对于每个复合物/单元,分别执行1个SQL语句,用于链接、图片、文档、事件和设施。

我的问题如下:

如果我正确地索引了所有表格,每个复合物/单元执行3-5个额外的查询真的是一个坏主意吗?

如果不是,还有什么其他方法可以获得所需的数据以加载到PHP对象中。理想情况下,我将为单元拥有以下对象:

Unit Object
(
    [id]
    [mls_number]
    [type]
    [retail_price]
    [investor_price]
    [quantity]
    [beds]
    [baths]
    [square_feet]
    [description]
    [featured]
    [year_built]
    [has_garage]
    [stories]
    [other_features]
    [investor_notes]
    [tour_link]
    [complex] => Complex Object
        (
            [id]
            [name]
            [description]
            etc.
        )
    [agent] => Agent Object
        (
            [id]
            [first_name]
            [last_name]
            [email]
            [phone]
            [phone2] 
            etc.

        )
    [pictures] => Array
        (
            [1] => Picture Object
                (
                )
        )
    [links] => Array
        (
            [1] => Link Object
                (
                )
        )
    [documents] => Array
        (
            [1] => Document Object
                (
                )
        )    
)

我并不总是需要所有这些信息,有时我只需要复杂对象的主键,有时我只需要代理商的主键等等。但我认为正确的做法是每次实例化时加载整个对象。

我一直在研究面向对象的PHP,但大多数(事实上全部)在线示例仅使用1个表格。显然,这对我正在处理的项目没有帮助,因为它具有许多复杂的关系。有什么想法吗?我是完全错乱了吗?

谢谢

[更新]

另一方面,通常在前端,所有人都会看到,我确实需要所有信息。例如,当有人想要获取特定综合体的信息时,我需要显示属于该综合体的所有单元、所有图片、文档、链接、综合体的事件以及所有单元的图片、文档和链接。

我希望避免的是,在一个页面加载期间,执行一次查询来获取我需要的综合体。然后再查询获取与综合体关联的20个单元。然后针对这20个单元,分别执行图片、文档、链接等查询。我希望一次性获得所有这些信息,并通过一次访问数据库来完成。

[编辑2]同时,请注意,从数据库中选择图片、文档、链接、事件和代理商的查询非常简单。只需基本的SELECT [列列表] FROM [表] WHERE [主键] = [值],偶尔使用INNER JOIN。我不进行任何复杂的计算或子查询,只是基础内容。

[BENCHMARK] 在阅读了我提出的问题的所有答案后,我决定对我决定要做的事情进行基准测试。我的做法是加载我所需的所有单位。然后,在我需要显示图片、文档等内容时,我会在那个时候加载它们。我创建了30,000个测试单位,每个单位都有100张图片、100个文档和100个链接。然后,我加载了一定数量的单位(我从1000个开始,然后是100个,最后是更加现实的10个),循环遍历它们,然后加载与该单位相关联的所有图片、文档和链接。使用1000个单位,大约需要30秒。使用100个单位,需要约3秒。使用10个单位,需要约0.5秒。结果存在很大的差异。有时候,使用10个单位只需要0.12秒。然后可能需要0.8秒。然后再是0.5秒。然后是0.78秒。真的是全都不一样。但是,平均而言,似乎大约需要半秒钟。然而,在实际情况下,我可能只需要一次性获取6个单位,它们每个都可能只有10张图片、5个链接和5个文档与它们相关联……因此,我认为“在需要时获取数据”的方法是这种情况下最好的选择。但是,如果您需要一次性获取所有这些数据,那么最好想出一个单一的SQL语句来加载您需要的所有数据,这样您只需要遍历一次数据(每次6700个单位需要217秒,而全部30,000个单位会使PHP内存溢出)。
5个回答

4
如果我正确地索引所有表格,为每个复杂/单元执行3-5个额外的查询是否真的是一个不好的想法?
简而言之,不是。对于每个相关表格,您应该运行一个单独查询。这是大多数ORM(对象关系映射/建模)系统所做的。
如果性能真的是一个问题(根据您所说的情况,它不会是),那么您可以考虑使用像APC,memcache或Xcache这样的缓存来缓存结果。

0

ORM 的重点不在于每次都加载整个对象,而在于使您的应用程序轻松透明地访问对象。

话虽如此,如果您需要单元对象,则只需加载单元对象,而不是整个对象。如果您需要代理对象,则在需要时加载它,而不是在加载单元对象时加载它。


最大的问题在于对于管理部分,这些块被分割以允许细粒度管理。但在前端,一个页面将显示一个复杂的所有单元格、所有相关图片、文档、事件和链接,以及分配的代理和联系人信息... - SpaDusA
由于您将通过索引列访问数据并实际使用它,因此这不应该是一个问题。我的答案是针对ORM所说的拉回所有数据,而不是因为它将被使用。 - longneck

0

我曾经在实验中自己设计MVC框架时,不得不解决这个问题。为了限制从数据库加载的数据层数,我将一个整数传递给构造函数。每个构造函数在将其传递给实例化对象的构造函数之前都会将此整数减少。当它变成0时,就不会再实例化子对象了。这基本上意味着传递的整数是加载的层数。

因此,如果我只想要单位对象的属性,我会这样做:

$myUnit = new Unit($unitId,1);

0
如果您想要“存储”对象,也就是缓存它们,只需将它们加载到 PHP 数组中并进行序列化。然后,您可以将其存储回数据库、内存缓存或任何其他地方。给它附加一个标签可以让您检索它,并包含一个时间戳,以便您知道它的年龄(即需要刷新)。
如果数据不会更改或很少更改,那么每次运行多个复杂查询的确没有必要。像获取主键这样的简单查询,您最好直接访问数据库。

我不想存储对象,我认为。我试图弄清楚的只是如何在PHP中高效地加载数据库中的信息。 - SpaDusA

0

也许你应该考虑将其分解。

当你初始化对象时,只获取该对象运行所需的详细信息。如果需要更多的细节,那么再去获取它们。通过这种方式分配负载和处理:对象只获取其运行所需的负载和处理,需要更多时,再获取它们。

因此,在你的例子中 - 首先创建复杂对象。当你需要访问一个单元时,再创建该单元;当你需要代理时,再获取该代理等。

$complexDetails = array('id' => $id, etc);
$complexUnits = array();
.........
$complexUnits[] = new unit();
.........
$complexDetails['agent'] = new Agent();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接