繁体   English   中英

在php和mysql中的嵌套查询循环上需要帮助吗?

[英]Need help on nested loop of queries in php and mysql?

我试图做到这一点:

<?php
  $good_customer = 0;
  $q = mysql_query("SELECT user FROM users WHERE activated = '1'"); // this gives me about 40k users

  while($r = mysql_fetch_assoc($q)){
    $money_spent = 0;

    $user = $r['user'];
    // Do queries on another 20 tables
    for($i = 1; $i<=20 ; $i++){
      $tbl_name = 'data' . $i;

      $q2 = mysql_query("SELECT money_spent FROM $tbl_name WHERE user = '{$user}'");
      while($r2 = mysql_fetch_assoc($q2)){
        $money_spend += $r2['money_spent'];
      }

      if($money_spend > 1000000){
        $good_customer += 1;
      }
    }
  }

这只是一个例子。 我正在本地主机上测试,对于单用户,它返回速度非常快。 但是,当我尝试使用1000时,它需要永远的时间,甚至没有提到40k用户。

无论如何要优化/改进此代码?

编辑:顺便说一下,其他20个表中的每个表都有〜20-40k记录

编辑2:

好的,放弃“花钱”的想法。 这是我当前的结构:

用户表=>用户是PK

logs_week_1表=>用户为FK。

logs_week_2表=>用户为FK

logs_week_3表=>用户是FK

……将来会有更多的日志表。

我想找到他们在我的网站上花费的“平均时间”,该时间存储在每个日志表中。

你们这么说,每周存储日志是个坏主意吗? 我应该合并成一张桌子吗?

听起来您的模型有问题。 为什么您有20个data而不是一个week data

那你可以做一个

Select user, Sum( money_spent ) As total_money_spent
From data
Group By user

甚至

Select Count(*) As good_customer_count
From data
Group By user
Having Sum( money_spent ) > 1000000

使用当前的结构,您只能执行以下操作:

Select u.user, d1.money_spent + d2.money_spent + ...
From users u
Join data1 d1 On ( d1.user = u.user )
Join data2 d2 On ( d2.user = u.user )
...

要么

Select Count(*) As good_customer_count
From
  ( Select d1.money_spent + d2.money_spent + ... As total_money_spent
    From data1 d1
    Join data1 d1 On ( d1.user = u.user )
    Join data2 d2 On ( d2.user = u.user )
    ...
  )
Where total_money_spent > 1000000

这肯定比您当前的解决方案要快。


并且花在页面上的时间应该存储在一个数字字段中。

由于Peter已经给出了一个很好的答案,我将只发布经过适当设计的查询外观(所有日志数据都放在一个表中)

SELECT user, AVG(TIMEDIFF(start_time, end_time)) AS average_time
FROM logs
GROUP BY user

您可以在上述条件中进一步应用条件,以仅获取特定时间段(周,月等)的统计信息,也可以按其他级别分组。

您还可以有效地在同一查询中获得MAX和COUNT(以及标准差和其他聚合函数 )。

当然,请注意使用较大的数据集以获得最佳性能的索引。

编辑:

就像我给彼得+1一样,我注意到他没有提到UNION ALL选项

因此,您可以(这不是最佳选择,并且不与其他人给出的设计问题警告相抵触)

SELECT user, AVG(TIMEDIFF(start_time, end_time)) AS average_time
FROM (
    SELECT * FROM log_week_1
    UNION ALL
    SELECT * FROM log_week_2
    UNION ALL
    SELECT * FROM log_week_3
    ...
) U
GROUP BY user

您也可以为此联合创建一个VIEW。

对于40k用户,您要创建1 + 20 * 40k查询。 无论如何这都会很慢。 停止将日志保存在20个表中。 您应该以其他方式设计数据库。 在适当设计的数据库上,所有这些都应通过1个查询来完成

SELECT count(user) as good_customers FROM users JOIN $tbl_name ON users.user = {$tbl_name}.user ON WHERE users.activated = '1' HAVING SUM(money_spent) > 100000.

在最坏的情况下,您还应该使用每个表的1个查询来完成全部操作。

SELECT user, SUM(money_spent) as money_spent FROM users JOIN $tbl_name ON users.user = {$tbl_name}.user ON WHERE users.activated = '1'.

然后将这20个money_spent列加起来即可得到答案。

您应该将在网站上花费的时间存储为数字(以分钟或秒为单位),而不是时间。 然后,您可以计算该值的平均值和总和。 并将您的日志保存在一个表中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM