2

我试图找出一种无需循环 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 号码的列表以及它在用户中列出的次数(在触发器更新时)。

目前,在进行白日梦编码时,我会从中获取所有 IP 的列表uniq_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,基于时间字段。

任何想法如何在一个查询中做到这一点?

4

2 回答 2

1

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

(IP,时间 DESC)

然后,试试这个查询。我错过了澄清的关键事情。HAVING 子句在任何 group-by 或 order-by 子句之后应用。因此,数据按 IP 地址和日期/时间降序的正确顺序预先返回,然后应用 @sql 变量。一旦记录符合条件并准备好添加到最终结果集中,就会应用 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
于 2012-04-29T01:06:19.130 回答
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
于 2012-05-04T13:20:25.920 回答