性能,sql 重联接与多个小请求


Performance, sql heavy join vs multiple small request

我有以下Mysql数据库结构

[Table - Category1]
  [Table Category1 -> Category2 ] (One to N relation)  
[Table - Category2]
  [Table Category2 -> Item ] (One to N relation) 
[Table - Item]

我想使用以下结构将所有内容放入 PHP 中的数组中

$arr[$i]['name'] = 'name of something in category1';
$arr[$i]['data'][$j]['name'] = 'name of something in category2';
$arr[$i]['data'][$j]['data'][$k]['name'] = 'name of something in item';

所以基本上我不知道我是否应该像下面这样使用带有 JOIN 的"重"sql 请求或使用迭代方法

加入请求

SELECT c1.name as c1name, c2.name as c2name, i.name 
FROM category1 c1 
LEFT JOIN category1_to_category2 c1tc2 ON c1.id = c1tc2.id_category1 
LEFT JOIN category2 c2 ON c1tc2.id_category2 = c2.id
LEFT JOIN category2_to_item c2ti ON c2.id = c2ti.id_category2
LEFT JOIN item i ON c2ti.id_item  = i.id

迭代方法

$sql = 'SELECT id, name FROM category1';
$result = $mysqli->query($sql);
$arr = array();
$i = 0;
while ($arr[$i] = $result->fetch_assoc()) {
    $join = $mysqli->query('SELECT c2.id, c2.name FROM category2 c2 LEFT JOIN category1_to_category2 c1tc2 ON c2.id = c1tc2.id_category 2 WHERE c1tc2.id_category1 = '.$arr[$i]['id']);
    $j = 0;
    while ($arr[$i]['data'][$j] = $join->fetch_assoc())
      /* same request as above but with items */
    $i++;
}

迭代解决方案将发出大约 10 * 20 个请求,这对我来说似乎很多,这就是为什么我会选择第一个解决方案(4 JOIN 单个请求)。但是,使用单请求解决方案,我的数组将如下所示

$arr[0]['c1name'];
$arr[0]['c2name'];
$arr[0]['iname'];

并且需要一些PHP操作才能获得所需的数组,我需要在HTML页面的选项卡中显示该数组。所以我的问题是,有一个大的SQL请求和一些PHP数组操作更好,还是有多个小请求没有PHP数组操作更好?我知道在大多数情况下,从SQL获取所有数据是一个更好的解决方案,但在这种情况下我不确定。顺便说一下,我唯一考虑的是网页的加载时间。

提前感谢您的帮助=)。

通常,让 SQL 服务器

执行尽可能多的数据格式化和迭代是更好的,您的示例也不例外,因为 SQL 服务器通常比普通编程语言更有效地完成任务。

除此之外,您

正在减少服务器的查询负载,并且您有充分的理由使用复杂的连接。

唯一的缺点是复杂的SQL查询可能难以格式化和调试,如果还没有使用第三方SQL工具,我建议购买一个。

为了配合Wobbles的答案(我同意),我建议您执行单个查询,但存储c1name,c2name和iname中每个键的最后一个键。当这些更改时,您将递增相关的数组下标,并再次初始化较低级别的下标以构建阵列。

像这样的东西:-

<?php
$sql = "SELECT c1.name AS c1name, c2.name AS c2name, i.name  AS iname
        FROM category1 c1 
        LEFT JOIN category1_to_category2 c1tc2 ON c1.id = c1tc2.id_category1 
        LEFT JOIN category2 c2 ON c1tc2.id_category2 = c2.id
        LEFT JOIN category2_to_item c2ti ON c2.id = c2ti.id_category2
        LEFT JOIN item i ON c2ti.id_item  = i.id"
$result = $mysqli->query($sql);
$arr = array();
$i = 0;
$j = 0;
$k = 0;
$c1name = '';
$c2name = '';
$iname = '';
while ($row = $result->fetch_assoc()) 
{
    switch(true)
    {
        case $row['c1name'] != $c1name :
            $i++;
            $j = 0;
            $k = 0;
            $arr[$i]['name'] = $row['c1name'];
            $arr[$i]['data'][$j]['name'] = $row['c2name'];
            $arr[$i]['data'][$j]['data'][$k]['name'] = $row['iname'];
            break;
        case $row['c2name'] != $c2name :
            $j++;
            $k = 0;
            $arr[$i]['data'][$j]['name'] = $row['c2name'];
            $arr[$i]['data'][$j]['data'][$k]['name'] = $row['iname'];
            break;
        default :
            $k++;
            $arr[$i]['data'][$j]['data'][$k]['name'] = $row['iname'];
            break;
    }
    $c1name = $row['c1name'];
    $c2name = $row['c2name'];
    $iname = $row['iname'];
}

另外,还有一些代码用于生成菜单。只有 2 个级别,它最初编码为第一级的一个查询,然后对第一级中的每个记录进行一个查询,以获取其下的所有项目。并不复杂(第一级只有~16个项目,平均每个项目下面不到10个项目)。我将其重写为单个联接查询。生成该菜单的典型时间从 0.25 秒下降到 0.004 秒。向数据库发送查询所花费的时间很容易迅速变得过多。