在MySQL上似乎并不缺少分层数据问题,但似乎他们主要讨论的是在数据库中管理这些数据或实际检索递归分层数据。我的情况既不是。我有一个需要显示的项目网格。每个项目也可以有0个或更多与之关联的注释。现在,项目及其数据都显示在网格中以及属于该项目的任何注释中。通常需要某种向下钻取,对话或其他用户操作来查看网格项的子数据,但在这种情况下,我们在同一网格中显示父数据和子数据。可能不符合事实上的标准,但事实就是如此。
现在,通过单独的MySQL查询检索网格中每个父项的注释。我立即畏缩,意识到必须为单个页面加载运行的所有完全独立的数据库查询。我没有描述过,但如果这是我们有时看到的慢页面加载的一部分,我不会太惊讶。我希望理想情况下将其归结为单个查询或者可能是2.但是,我很难想出一个听起来比现在更好的解决方案。
我的第一个想法是使用某种分隔符(例如“|”)来平展每行的注释子项然后在渲染页面时将它们拆分为PHP。与此相关的问题是,必须将注释中的每个字段分开,然后每个注释,然后考虑数据中分隔符字符的可能性,这变得越来越复杂。维护和调试只是一团糟。
我的下一个想法是将外部联接注释到项目,并只考虑PHP中的项目重复项。我正在使用Codeigniter的数据库库,它返回一个用于数据库数据的PHP数组。这听起来像生成的数组中可能存在大量重复数据,这可能会对较大的结果集产生系统性负担。我认为在大多数情况下它不会太糟糕,所以这个选项目前在我的可能性列表的顶部。理想情况下,如果我正确理解MVC,我应该尽可能地保持我的数据库,业务逻辑和视图/显示。因此,理想情况下,模型返回的数据中不应出现任何数据库“怪癖”(缺少更好的词)。也就是说,无论从这个模型方法中获取数据,都不应该关注像这样的重复数据。所以我必须添加一个额外的循环来以某种方式消除重复的项数组条目,但只有在我检索了所有子注释并将它们放入自己的数组之后。
两个查询是另一个想法,但后来我必须在SQL语句中传递大量项目ID以供注释,然后在PHP中手动将所有数据压缩在一起。
我的目标不是放弃在这里工作,但我希望有一些我没有想到的更优化(资源密集度更低,编码器更少混淆)的方法。
答案 0 :(得分:2)
正如您在问题中所述,使用联接会带来大量重复信息。它应该很简单,可以在PHP中删除,但为什么要首先将它删回?
使用从查询中检索的ID列表编译SQL语句应该不是问题(请参阅cwallenpoole's answer)。或者,您可以创建一个子查询,以便MySQL为您重新创建ID列表 - 这取决于子查询的密集程度。
选择您的商品:
SELECT * FROM item WHERE description = 'Item 1';
然后选择这些项目的评论:
SELECT * FROM comment WHERE item_id IN (
SELECT id FROM item WHERE description = 'Item 1'
);
答案 1 :(得分:2)
在大多数情况下,我使用某种ORM Lazy-Loading system解决了这类问题,但看起来并不像你选择那样。
您是否考虑过:
基本上(伪代码)
$stmt = $pdo->query("SELECT ID /*columns*/ FROM ENTRIES");
$entries = array();
foreach( $row as $stmt->fetchAll(PDO::FETCH_ASSOC) )
{
$row['child-entities'] = array();
$entries[$row['id']] = $row;
}
$ids = implode(',',array_keys($entries));
$stmt = $pdo->query("SELECT PARENT_ID /*columns*/ FROM children WHERE PARENT_ID IN ($ids)");
foreach( $row as $stmt->fetchAll(PDO::FETCH_ASSOC) )
{
$entries[$row['parent_pid']]['child-entities'][] = $row;
}
$entries
现在将是一个关联数组,父项与子项直接关联。除非需要递归,否则这应该是两个查询中的所有内容。