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

标签 php mysql orm kohana

我目前正在使用php和mysql设计一个应用程序,构建在kohana框架上。我正在使用内置的orm,它被证明是非常有用的。一切正常,但我非常关心在某些页面上运行的查询数。
设置
例如,有一个页面,您可以在该页面上查看一个类别,该类别包含许多部分,而这些部分又包含许多产品。这是以表格形式列出的。每个产品都有(可能)许多属性、标志、层定价中断。所有这些都必须在表中表示。
有多少问题?
就查询而言:类别必须查询其中的所有部分,这些部分必须查询其中包含的所有产品。还不错,但是每个产品都必须查询它的所有产品属性、层定价和标志。因此,在一个类别中添加更多的产品会使查询增加很多倍(因为我目前主要使用orm)。在一个部分中有几百个产品将导致几百个查询。小问题,但这仍然是不好的。
到目前为止…
所有的钥匙都有索引。我可以用一个查询(见下面的编辑)提取所有信息,但是,正如您所想象的那样,这将导致每个产品、每个额外的(例如)属性、标志等在多行中分布大量冗余数据。
我并不反对放弃or m来显示应用程序的一部分,而使用查询构建甚至原始sql。
解决这个问题的方法其实很简单,而我现在对此一无所知,老实说,这是一种解脱。或许不是。我不确定。如果我的任何解释不足以理解这个问题的话,尽管问,我会尽量举一个更好的例子。(编辑:给出了更好的例子,见下文)
不过,旁注…
不过,有一点可能是有关联的:虽然我一直希望让应用程序设计得最高效,但这不是一个每天会被点击几十次或数百次的网站。它更像是一个管理应用程序,可能不会同时被几个人使用。我无法预见会有太多的重新加载,因为页面上的大多数数据编辑都是通过ajax完成的。所以,我是否应该同样关心,如果在这个页面上,每次加载这个特定页面时,它都在运行几百个查询(取决于当前查看的部分中有多少产品)。只是一个侧面的想法,即使是这样,如果有可能解决前面提到的主要问题,我宁愿这样。
非常感谢你!
编辑
根据几个答案,我似乎没有充分解释自己。所以,让我举个例子让你看看发生了什么。
在这个例子之前,我还应该做两个澄清:(1)也有一些多对多的关系,(2)你可以把我所寻找的比作交叉表查询。
让我们简化一下,假设我们有3个主表:
产品(产品ID、产品名称、添加的产品日期)
产品属性(产品属性ID、产品ID、值)
通知(通知ID、通知标签)
和1个旋转距骨:
产品通知(通知ID、产品ID)
我们要把所有的产品列在一张桌子上。在orm中调用所有产品就足够简单了。
因此,根据每个“产品”,我们列出了产品名称和添加的产品日期。但是,我们还需要列出所有的产品属性。每个产品有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; 
   }
 }

这当然过于简单化了,但这是我所说的原则。这已经很好了。但是,正如您所看到的,对于每个产品,它必须查询其所有属性以获得适当的集合或行。
函数的作用是:返回以下行的查询结果:
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来渲染显示——好吧,这正是现在许多软件架构师所建议的。编写一个完全不同的接口(带有自己优化的查询)来读取和报告数据。“read”模型可以查询与orm支持的“write”模型一起使用的同一个数据库,也可以是一个单独的数据库,为需要生成的报表/屏幕进行非规范化和优化。
看看这两个演示。听起来可能有点过头了(如果你的性能要求很低的话也可能是这样),但令人惊讶的是,这种技术如何让这么多问题消失了。
Udi Dahan: "Command-Query Responsibility Segregation"
Greg Young: "Unshackle Your Domain"

关于php - 使用许多一对多关系(ORM)减少MySQL中的查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4092784/

相关文章:

javascript - 使用 javascript 添加带有数据库值的下拉框的新行?

php - 优化阻塞数据库的 MySQL DELETE 查询

php - 为 Joomla 或 PHP 网站准备 Mysql 数据库

php 到 MySQL 不工作,不知道为什么

php - MySQL语法错误

php - 将 HTML-PHP 表导出/下载到 Excel 文件

javascript - sequelize - 带有关联的 Where 子句

java - 传递分离实体以将 Spring 持久化为一对多关系

python - 在 Django 中使用具有相同值的不同模型字段

PHP - Guzzle\Http\Exception\CurlException - Craft CMS