用于收集带限制的分组子集的子查询

时间:2012-04-28 16:49:19

标签: mysql subquery limit

我正试图想出一种收集数据集的方法,而不必循环700,000次mysql查询。

我有两张桌子

users

id autoincrement, 
time timestamp, 
username varchar(200), 
email varchar(100), 
ip varchar(20)

uniq_ip

ip unique varchar(20), 
most_recent datetime, 
count (int)

users有2500万行,记录用户在网站上工作时的活动。 uniq_ip列出了所有IP号码以及在用户中列出的次数(触发更新时)。

目前,在进行白日梦编码时,我会从uniq_ip获取所有IP的列表并循环它们以获取每个IP的最新2000条记录。由于uniq_ip有700,000行,这个循环非常讨厌,使用

总计700,000个查询
select * from users where ip = '$outerloopip' order by `time` desc limit 2000;

我正在尝试获取一个查询,该查询将获取每个IP的最新2000个列表。如果1.2.3.4被列出10,000次,我只想要最近的2000,基于时间字段。

如何在一个查询中执行此操作?

2 个答案:

答案 0 :(得分:1)

对于之前的回答感到抱歉,重新阅读并应用了更新的查询。我错过了,并认为你只想要最近的2000个IP地址。无论如何,这个地址会执行所有IP地址,并将每个IP的总记录限制为2,000个条目,最近一个位于顶部。我会确保你有一个索引

(IP,TIME DESC)

然后,尝试此查询。我错过了澄清的关键事项。 HAVING子句在任何group-by或order-by子句之后应用。因此,数据按正确的IP地址和日期/时间DESCENDING顺序预先返回,然后应用@sql变量。一旦记录被限定并且READY被添加到最终结果集,就应用HAVING子句。在那一刻,它查看了序列计数器并说...如果它大于2000,则抛出它并继续下一条记录。

根据我的原始查询,它正在保存所有内容,然后循环第二次并踢出超过2000的那些,这可能就是为什么它会让你的磁盘空间消失。

select
      U.*,
      @LastSeq := IF( @LastIP = U.IP, @LastSeq +1, 1 ) as IPSequence,
      @LastIP := U.IP as carryForNextRecord
   from 
      ( select @LastIP := '', @LastSeq := 0 ) sqlvars,
      Users U
   order by
      U.IP,
      U.time DESC
   having 
      IPSequence <= 2000

答案 1 :(得分:0)

SELECT ip as IP ,
     (SELECT GROUP_CONCAT(time)     FROM users WHERE ip = IP ORDER BY time DESC LIMIT 2000) as Time,
     (SELECT GROUP_CONCAT(username) FROM users WHERE ip = IP ORDER BY time DESC LIMIT 2000) as UserName,
     (SELECT GROUP_CONCAT(email)    FROM users WHERE ip = IP ORDER BY time DESC LIMIT 2000) as Email
FROM uniq_id