繁体   English   中英

使用许多一对多关系(ORM)减少MySQL中的查询

[英]Decreasing queries in MySQL with many one-to-many relationships (ORM)

我目前正在使用基于Kohana框架构建的PHP和MySQL设计应用程序。 我正在使用内置的ORM,事实证明它非常有用。 一切正常,但我非常关心在某些页面上运行的查询数量。

设置
例如,有一个页面,您可以在其中查看充满各个部分的类别,这些部分又包含产品。 这以表格格式列出。 每个产品都有(可能)许多属性,标志,等级定价中断。 这必须全部在表格中表示。

有多少疑问?
就查询而言:类别必须查询其中的所有部分,并且这些部分必须查询它们包含的所有产品。 还不错,但每个产品必须查询它的所有产品属性,层定价和标志。 因此,向类别添加更多产品会使查询多次增加(因为我目前主要使用ORM)。 在一个部分中有几百个产品将导致几百个查询。 小问题,但仍然不好。

至今...
所有键都被编入索引。 我可以使用单个查询提取所有信息(请参阅下面的编辑),但是,正如您所能想象的那样,每个额外(例如)属性,这将导致每个产品在多行中分布大量冗余数据,国旗等

我并不反对放弃ORM来显示应用程序的部分并继续使用查询构建甚至原始SQL。

对此的解决方案实际上可能非常简单,我现在只是对它一无所知,老实说这是一种解脱。 或许它不是。 我不确定。 如果我的任何解释都不足以理解问题,那就问一下,我会试着给出一个更好的例子。 (编辑:给出更好的例子,见下文

虽然,旁注...但有一点可能有一些相关性:虽然我总是希望最有效地设计应用程序,但这不是一个每天会被打几十次或几百次的网站。 它更像是一个管理应用程序,可能不会被多个人同时使用。 我无法预见太多的重新加载,因为页面上的大部分数据编辑都是通过AJAX完成的。 那么,如果在这个页面上运行了几百个查询(当前查看的部分中有多少产品不一致),每次加载此特定页面时,我是否应该关注多少? 只是一个想法,即便如此,如果有可能解决上述主要问题,我宁愿这样做。

非常感谢你!

编辑
基于几个答案,似乎我没有充分解释自己。 所以,让我发一个例子让你看看发生了什么。 在这个例子之前,我还应该做两个澄清:(1)还有一对多对多的关系,(2)你可能把我正在寻找的东西比作交叉表查询。

让我们简化并说我们有3个主表:产品(product_id,product_name,product_date_added)product_attributes(product_attribute_id,product_id,value)通知(notification_id,notification_label)

和1个支点talbe:product_notifications(notification_id,product_id)

我们将列出表格中的所有产品。 在ORM中调用所有产品非常简单。 因此,根据每个“产品”,我们会列出product_name和product_date_added。 但是,我们还需要列出所有产品属性。 每种产品有0或更多。 我们还必须显示产品的通知,其中还有0或更多。 所以目前,它的工作原理基本上是:

foreach ($products->find_all() as $product) //given that $products is an ORM object
{
   echo $product->product_id; //lets just pretend these are surrounded by html
   echo $product->product_name;
   foreach ($products->product_attributes->find_all() as $attribute)
   {
       echo $attribute->value;
   }
   foreach ($products->notifications->find_all() as $notification)
   {
       echo $notification->notification_label; 
   }
 }

这当然过于简单,但这是我所说的原则。 这已经伟大工程 但是 ,正如您所看到的,对于每个产品,它必须查询其所有属性以获取适当的集合或行。 find_all()函数将返回以下行的查询结果: SELECT product_attributes.* FROM product_attributes WHERE product_id = '#' ,类似于通知。 它为每个产品进行了这些查询。
因此,对于数据库中的每个产品,查询数量是该数量的几倍。 因此,尽管效果很好,但它不能很好地扩展,因为它可能会导致数百个查询。

如果我执行查询以获取一个查询中的所有数据,则执行以下操作:

SELECT p.*, pa.*, n.*
FROM products p
LEFT JOIN product_attributes pa ON pa.product_id = p.product_id
LEFT JOIN product_notifications pn ON pn.product_id = p.product_id
LEFT JOIN notifications n ON n.notification_id = pn.notification_id

(再次过度简化)。 这将获取数据本身,但根据产品的每个属性和通知,将返回带有冗余信息的额外行。

例如,如果我在数据库中有两个产品; 一个有1个属性和1个标志,另一个有3个属性和2个标志,它将返回:

product_id, product_name, product_date_added, product_attribute_id, value, notification_id, notification_label
1, My Product, 10/10/10, 1, Color: Red, 1, Add This Product
2, Busy Product, 10/11/10, 2, Color: Blue, 1, Add This Product
2, Busy Product, 10/11/10, 2, Color: Blue, 2, Update This Product
2, Busy Product, 10/11/10, 3, Style: New, 1, Add This Product
2, Busy Product, 10/11/10, 3, Style: New, 2, Update This Product

不用说,这是一个很多冗余的信息。 每个产品返回的行数将是它拥有的通知数量的属性数。

ORM(或者,通常只是在循环中创建新查询)将每行中的所有信息合并到它自己的对象中,从而允许更逻辑地处理数据。 那是摇滚乐。 在一个查询中调用信息消除了对可能数百个查询的需要,但是在行中创建了大量冗余数据,因此不会以简洁的集合返回(一个/多个)到多个关系数据。 那是个难点。

对不起,这么久,试图彻底,哈哈,谢谢!

一个有趣的替代方案是使用完全独立的模型处理您的读取和写入。 (命令查询分离)。 复杂的对象模型(和ORMS)非常适合于复杂的业务行为建模,但是作为查询和向用户显示信息的接口很糟糕。 你提到你并不反对放弃使用ORM渲染显示器 - 嗯,这正是许多软件架构师现在提出的建议。 编写一个完全不同的界面(具有自己的优化查询),用于读取和报告数据。 “读取”模型可以查询与ORM支持的“写入”模型一起使用的相同数据库,也可以是针对您需要生成的报告/屏幕进行非规范化和优化的单独数据库。

看看这两个演示文稿。 这可能听起来有点矫枉过正(如果你的性能要求非常低,可能就是这样),但是这种技术让这么多问题消失的感觉真是太棒了。

一个好的ORM应该为你处理这个问题。 如果您认为必须手动执行此操作,则可以执行此操作。

在单个查询中获取所需的所有类别,并将主键ID存储在PHP数组中。

运行类似这样的查询:

mysql_query('SELECT yourListOfFieldsHere FROM Products WHERE Product_id IN ('.implode(',', $categoryIDs).')');

这应该为您提供单个查询中所需的所有产品。 然后使用PHP将这些映射到正确的类别并相应地显示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM