2010-11-04 90 views
4

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

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

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

到目前为止......
所有的键都被编入索引。我可以通过一个查询来获取所有信息(请参阅下面的编辑),但是,正如您可以想象的那样,这将导致大量冗余数据分布在每个产品的多行中,每个额外(例如)属性,国旗等

我不反对放弃ORM的应用程序的显示部分,并与查询建立甚至原始的SQL去。

这样做的解决方案实际上可能非常简单,我现在只是无知,这将是一个诚实的救济。或者,也许不是。我不确定。如果我的任何解释都不足以理解问题,那就问一问,我会试着举一个更好的例子。 (编辑:给出最好的例子,请参见下面

虽然一个侧面说明... 一两件事,可能有一定的关联,虽然:虽然我一直希望能有最有效地设计应用程序,这ISN”这个网站每天要打几十次或几百次,这更像是一个管理应用程序,可能一次不会被超过几个人使用,我不能预见太多的重新加载,因为大多数页面上的数据编辑都是通过AJAX完成的,因此,如果在这个页面上运行几百个查询(当前查看的部分有多少产品波动),那么我应该多关心这个特定的每一次页面被加载?只是一边思考,即使如此,如果有可能的话为了解决上述主要问题,我宁愿这样做。

非常感谢!

编辑
基于几个答案,似乎我没有充分解释自己。所以,让我发表一个例子,以便了解发生了什么。在这个例子之前,我还应该做两点澄清:(1)也有一对多对多的关系,(2),您可以将我正在寻找的内容与交叉表查询相比较。

让我们简化和说,我们有3个主要的表: 产品(产品,PRODUCT_NAME,product_date_added) product_attributes(product_attribute_id,PRODUCT_ID,值) 通知(notification_id,notification_label)

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

我们将列出所有产品的表格。在ORM中调用所有产品很简单。 因此,根据每个'产品',我们列出了product_name和product_date_added。但是,我们还需要列出所有产品属性。每个产品有一个或多个这些。我们还必须显示产品有哪些通知,其中有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(或者,通常在循环中创建新的查询)将每行中的所有信息合并到它自己的对象中,从而允许更加逻辑地处理数据。那是摇滚乐。在一个查询中调用信息可以消除数百个查询的需要,但会在行中创建大量冗余数据,因此不会以简洁集返回(一个/多个)至多个关系数据。这是困难的地方。

对不起,这是很长的,试图彻底,哈哈,谢谢!

+0

一个良好的ORM应该让你指定要装什么东西在初始查询连接的延迟加载它们与单独的查询后,而不是... – Amber 2010-11-04 00:07:53

+0

只是为了参考,你可以运行'Database :: instance() - > last_query'并向我们展示ORM生成的一些查询吗?哦,还有+1,这是一个深思熟虑的问题(最近1个代表用户变得更加稀少)。 – alex 2010-11-04 00:20:02

+1

我编辑了问题描述以包含正在生成的查询的简要示例。谢谢你!就JOINS而言,我也编辑过,以显示在尝试加入此数据时发生的情况。希望上面公布的示例数据更清楚地表明问题是什么以及我想要克服什么。非常感谢! – aaronofleonard 2010-11-04 17:03:50

回答

1

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

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

+0

非常感谢您的意见,我将检查这些演示文稿并了解他们如何提供帮助,并牢记第一段。非常感谢你! – aaronofleonard 2010-11-04 16:15:34

0

一个好的ORM应该为你处理这个问题。如果你觉得你必须手动完成,你可以这样做。

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

运行类似这样的查询:

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

这应该给你一切,你在单个查询所需要的产品。然后使用PHP将这些映射到正确的类别并相应显示。

+0

只要提供Kohana的方式,那就是'Db :: query(Database :: SELECT,$ query) - > execute() - > as_array()'。 – alex 2010-11-04 00:27:10

+0

ORM处理这个问题。产品选择不是问题;我想我在问题描述中没有足够好地解释自己,对不起! – aaronofleonard 2010-11-04 16:16:13