【问题标题】:MySQL - Is it possible to merge select queries, so it doesn't have to be executed in while loop?MySQL - 是否可以合并选择查询,因此不必在 while 循环中执行?
【发布时间】:2019-11-06 16:50:10
【问题描述】:

所以我有一个查询,它将获取有关项目不可见的匹配行的所有信息。

现在在 while 循环中,我不得不使用 select count 查询来计算每个用户有多少不可见的项目,如果循环中有这么多结果,这将花费太多时间。

有没有办法在while循环中不运行select查询来查询它?

例如:

SELECT  categories.name, 
        quality.name, 
        users.regdate,
        categories.name,
        items.name, 
        items.visible,
        items.owner,
        users.username
        FROM items
        LEFT JOIN users ON items.owner = users.id 
        LEFT JOIN categories ON items.category = categories.id 
        LEFT JOIN quality on items.category_quality = quality.id
        WHERE items.visible = 'no'

现在在 while 循环中获取项目数,我必须查询

while($row = mysqli_fetch_assoc($sql))
{
$all_items_by_user = "SELECT COUNT(items.name)
FROM items
WHERE items.owner = ".$row['owner']."";

$visible_items_by_user = "SELECT COUNT(items.name)
FROM items
WHERE items.owner = ".$row['owner']." AND items.visible = 'yes'";

// rest of code here.
// when there are 200 items in loop executing time goes crazy 
// (6+ secs, where with 1 item it's around 0.05)
}

用示例编辑:

有些人想看看最终的代码是什么,我会尽力做到最好。

忽略左连接,因为这不是相关的,我只是从整个查询中添加了这些。

Id | item name | owner | Visible
1 | Item 1 | 2 | no
2 | Item 2 | 2 | yes
3 | Item 3 | 2 | no
4 | Item 4 | 2 | no
5 | Item 5 | 2 | no
6 | Item 6 | 3 | no
7 | Item 7 | 3 | no
8 | Item 8 | 3 | no
9 | Item 9 | 4 | no
10 | Item 10 | 4 | no

在每个用户的 while 循环中,它应该计算用户拥有的行数。

例如: 用户 2 共有 5 行,隐藏 4 行,($all_items_by_user 将计算所有内容,而 $visible_items_by_user 将仅计算 1) 用户 3 拥有 3 行, 用户 4 拥有 2 行。

如何计算每个用户的项目,因为如果我在 while 循环之外进行,它将只计算第一个用户,而不是每个用户。

最终结果应该是

while($row = mysqli_fetch_assoc($sql))
{
$all_items_by_user = "SELECT COUNT(items.name)
FROM items
WHERE items.owner = ".$row['owner']."";

$visible_items_by_user = "SELECT COUNT(items.name)
FROM items
WHERE items.owner = ".$row['owner']." AND items.visible = 'yes'";

echo $row['owner'] . "(Visible items: number | All items: number";
// Output: 2 (Visible items: 1 | All items: 5)
}

【问题讨论】:

标签: php mysql loops


【解决方案1】:

这假设您仅关心每个用户的计数,并且您不关心任何项目的特定信息

SELECT items.owner,
    COUNT(items.name) AS itemCount, 
    SUM( CASE WHEN items.visible = 'yes' AND item.name IS NOT NULL
            THEN 1 ELSE 0 END) AS visibleCount
    FROM items 
    GROUP BY items.owner

然后您只需遍历每一行,这将为您提供用户、该用户的总计数以及该用户的可见计数。

DEMO

【讨论】:

  • 谢谢。我是否需要添加 union 或 join 以使其与原始查询一起使用以获取所有信息?
【解决方案2】:

您可以避免使用聚合结果子查询的连接进行循环查询

SELECT  categories.name, 
        quality.name, 
        users.regdate,
        categories.name,
        items.name, 
        items.visible,
        items.owner,
        users.username,
        ifnull(t.count_name,0), 
        ifnull(t.count_visible_name,0)
        FROM items
        LEFT JOIN users ON items.owner = users.id 
        LEFT JOIN categories ON items.category = categories.id 
        LEFT JOIN quality on items.category_quality = quality.id 
        LEFT JOIN  (
          select items.owner
            , COUNT(items.name) count_name
            , sum( case when items.visible = 'yes' AND item.name is not null
                then 1 else 0 end) count_visible_name
          from items 
          group by items.owner

        ) t on t.owner = items.owner 

确保你有正确的复合索引

 on table  items column(owner, category, category_quality)

【讨论】:

  • 子查询有必要吗?您不能在外部 SELECT 中应用计数和总和吗? (不是说你错了,我也没多想)
  • @PatrickQ 为了获得更好的性能,最好使用单个查询尊重一个主查询,然后是一个循环,如果你不这样做,则在循环中使用几对查询(主查询中的每个结果都有一对)不喜欢我的建议,您可以使用 suquery 而不是在循环中使用的查询对..无论如何..首先您应该检查 fot 有效结果..然后您可以选择您喜欢的..
  • 我不是 OP。我只是从优化的角度问。我可能是错的,但子查询只是觉得没有必要。
  • @PatrickQ .. 然后发布你的答案 .. 是更好的方法 .. .. 我认为子查询很有用,因为似乎还有其他连接可以干扰 .. 但你可能是对的。 . .. 如果所有者拥有多个 items.id,则所有者的计数是不一样的。在这种情况下,子查询是必要的 ..无论如何您的评论很有趣...谢谢
  • 我不知道态度不好从何而来。我只是在问一个问题,并可能建议对您的答案进行改进。我宁愿帮助改进您的问题,也不愿发布一个几乎相同的问题。没有必要为此辩护。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-11
  • 2013-05-13
  • 2012-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-04
相关资源
最近更新 更多