性能,sql重连接vs多个小请求

时间:2014-11-20 10:45:55

标签: php mysql

我有以下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';

所以基本上我不知道我是否应该使用一个" heavy"使用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 traitement来获取我需要在HTML页面的选项卡中显示的所需数组。所以我的问题是,有一个大的SQL请求与一些PHP数组操作或没有PHP数组操作有多个小请求更好吗?我知道在大多数情况下,从SQL获取所有数据是一个更好的解决方案,但在这种情况下,我不确定。顺便说一句,我唯一的考虑是我的网页加载时间。

提前感谢您的帮助=)。

2 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

要使用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秒。将查询发送到数据库的时间很容易过快。