我想要做到这一点:
<?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;
}
}
}
这只是一个例子。我在localhost上测试,对于单个用户,它返回非常快。但是当我尝试1000时,它需要永远,甚至没有提到40k用户。
无论如何要优化/改进此代码?
编辑: 顺便说一下,其他20个表中的每个表都有大约20到40k的记录
EDIT2:
好的,放弃“花钱”的想法。这是我目前的结构:
user table =&gt;用户是PK
logs_week_1 table =&gt;用户是FK。
logs_week_2 table =&gt;用户是FK
logs_week_3 table =&gt;用户是FK
...将来会有更多的日志表。
我想找到他们在我的网站上花费的“平均时间”,该时间存储在每个日志表中。
所以你们这么说,每周存储日志是一个坏主意?我应该合并到一个表中?
答案 0 :(得分:2)
听起来你的模型有问题。为什么你有20个data
- 表而不是一个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
这肯定会比您当前的解决方案更快。
页面上花费的时间应存储在数字字段中。
答案 1 :(得分:1)
正如Peter已经给出了一个很好的答案,我将只发布查询如何通过适当的设计(所有日志数据在一个表中)看起来
SELECT user, AVG(TIMEDIFF(start_time, end_time)) AS average_time
FROM logs
GROUP BY user
您可以进一步申请上述条件以获取统计数据仅限一段时间(周,月等),或者您也可以按其他级别分组。
您还可以在同一查询中获得MAX和COUNT(以及标准差和other aggregate function)。
当然,请使用较大的数据集来处理索引以获得最佳性能。
编辑:
就像我给彼得+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。
答案 2 :(得分:0)
您应该将在网站上花费的时间存储为数字(以分钟或秒为单位),而不是时间。然后,您可以计算此值的平均值和总和。并将您的日志保存在一个表中。
答案 3 :(得分: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列,你就得到了答案。