0

我正在努力做到这一点:

<?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

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

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

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

4

4 回答 4

2

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

然后你可以做一个

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

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


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

于 2010-04-21T05:31:15.583 回答
1

由于彼得已经给出了一个很好的答案,我只会发布正确设计的查询外观(一个表中的所有日志数据)

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

你也可以为这个联合创建一个视图。

于 2010-04-21T06:17:57.390 回答
0

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

于 2010-04-21T05:56:37.283 回答
0

对于 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 列相加,您就有了答案。

于 2012-12-11T07:01:05.657 回答