【问题标题】:PHP/MySQL OOP: Loading complex objects from SQLPHP/MySQL OOP:从 SQL 加载复杂对象
【发布时间】:2010-11-23 20:44:18
【问题描述】:

所以我正在为房地产经纪人做一个项目。我的设计中有以下对象/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 中,以便在我的项目中使用它们。

如果我尝试在 1 个查询中选择表中的所有数据,使用 LEFT JOINS,我将获得每个唯一的至少(链接数)*(图片数)*(文档数)行单元。向其中添加便利设施和事件,我将得到所有这些 * # ofities * # of events for each complex...不确定我是否想尝试将其加载到 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
                (
                )
        )    
)

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

我一直在对 OO PHP 进行大量研究,但大多数(阅读全部)在线示例仅使用 1 个表。这显然无济于事,因为我正在从事的项目有许多复杂的关系。有任何想法吗?我在这里完全不合时宜吗?

谢谢

[更新]

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

我希望避免的是,在一页加载期间,执行一个查询以获得我需要的复杂性。然后另一个查询以获取与复合体关联的 20 个单元。然后对于 20 个单元中的每一个,执行一个图片查询、另一个文档查询、另一个链接查询等。我想一次获得所有这些,一次通过数据库。

[编辑 2] 另外,请注意,从数据库中选择图片、文档、链接、事件和代理的查询非常简单。只是基本的 SELECT [list of columns] FROM [table] WHERE [primary_key] = [value],偶尔有 INNER JOIN。我没有做任何复杂的计算或子查询,只是基本的东西。

[基准] 因此,在阅读了我的问题的所有答案后,我决定对我决定做的事情进行基准测试。我所做的是加载我需要的所有单元。然后因为我需要显示图片,文档,等等等等,我在那个时候加载它们。我创建了 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 内存不足)。

【问题讨论】:

    标签: php mysql oop


    【解决方案1】:

    如果我正确索引所有表,那么为每个复杂/单元执行 3-5 个额外查询真的是个坏主意吗?

    简而言之,不。对于每个相关的表,您可能应该运行一个单独的查询。这就是大多数 ORM(对象关系映射/建模)系统会做的事情。

    如果性能确实是个问题(并且根据您所说,它不会是)那么您可能会考虑使用 APC、memcache 或 Xcache 之类的东西来缓存结果。

    【讨论】:

      【解决方案2】:

      ORM 的重点不是每次都加载整个对象。关键是让您的应用访问对象变得简单和透明。

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

      【讨论】:

      • 最大的问题是,对于管理部分,这些部分是分段的,以便进行细粒度的管理。但是在前端,一页会显示一个综合体,它的所有单元,所有相关的图片,文档,事件和链接以及分配的代理和联系信息......
      • 因为您将通过索引列访问数据并实际使用所有数据,所以这应该不是问题。我的回答是为了撤回所有数据,因为 ORM 是这么说的,而不是因为它将被使用。
      【解决方案3】:

      也许你应该考虑分手。

      当您启动您的对象时,只获取该对象运行所需的详细信息。如果以及当您需要更多详细信息时,请去获取它们。您可以通过这种方式分配负载和处理:对象仅获取其运行所需的负载和处理,当需要更多时,它会得到它。

      因此,在您的示例中 - 首先创建复合体。当您需要访问一个单元时,然后创建该单元,当您需要代理时,然后获取该代理等等。

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

      【讨论】:

        【解决方案4】:

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

        所以如果我只想要单元对象的属性,我会这样做:

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

        【讨论】:

          【解决方案5】:

          如果您想“存储”对象,即缓存它们,只需将它们加载到 PHP 数组中并对其进行序列化。然后,您可以将其存储回数据库、内存缓存或其他任何地方。将标签附加到它可以让您检索它,并包含一个时间戳,以便您知道它有多旧(即需要刷新)。

          如果数据没有变化,或者变化不频繁,那么确实没有理由每次都运行多个复杂的查询。简单的,比如得到一个primary,你还不如直接打数据库。

          【讨论】:

          • 我不想存储对象,我不这么认为。我想弄清楚的是如何在 PHP 中有效地加载数据库中的信息。
          猜你喜欢
          • 2012-02-22
          • 1970-01-01
          • 2018-03-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多