如何使分组优化?

23c0lvtd  于 2021-06-18  发布在  Mysql
关注(0)|答案(4)|浏览(332)

我的问题是:

EXPLAIN SELECT Count(1), 
       user_id, 
       type 
FROM   (SELECT e.user_id, 
               e.type, 
               Max(r.date_time) last_seen, 
               e.date_time      event_time 
        FROM   events e 
               JOIN requests r 
                 ON e.user_id = r.user_id 
                    AND e.type IN( 3, 5, 6 ) 
        GROUP  BY e.user_id, 
                  e.date_time, 
                  e.type 
        HAVING last_seen < event_time) x 
GROUP  BY user_id, 
          type

这也是 EXPLAIN :

下面是子查询的结果( x ) EXPLAIN :

看到了吗?非常理想。所以这里的问题是分组。你知道我怎样才能让这个问题变得更好吗?
编辑:我们需要两张table: requests 表--对于每个用户的请求,将在其中插入一个新行。所以,最后一个(最大的)在一定程度上决定了用户最后一次上网的时间。 events 表--对于每个答案、注解,将在其中插入新行。
我们说的是一个问答网站。我们所要做的就是“给那些在我们网站上最后一次在线后得到新评论/答案的用户发送一封电子邮件”。

eagi6jfj

eagi6jfj1#

表上需要适当的索引来匹配where子句和order by,以帮助优化。

table      index on...
events     ( type, user_id, date_time )
requests   ( user_id, date_time )

我甚至可以建议稍微调整一下我的问题。
改变你的想法

AND e.type IN( 3, 5, 6 )

WHERE e.type IN( 3, 5, 6 )

因为“e.type”基于查询的主表,与请求表的实际联接无关。联接应该表示实际的列,以便在表之间进行限定。
建议张贴编辑到问题。我可以提供另一种选择。在用户表中为“lastrequest”日期/时间字段添加一列。然后,每当为该用户输入请求时,更新user表中的字段。您不需要保留subquery max()来确定何时。这可能会将您的查询简化为。。。随着请求表变大,查询时间也会变长。通过直接查看用户表一次已知的最新请求,您就得到了答案。查询10k用户或2mil请求。。。你的选择是:)

select 
      u.user_id,
      e.type,
      count(*) CountPerType,
      min( e.date_time ) firstEventDateAfterUsersLastRequest
   from
      user u
         join events e 
            on u.user_id = e.user_id
           AND e.type in ( 3, 5, 6 )
           AND e.date_time > u.lastRequest
   group by
      u.user_id,
      e.type

因此,您的加入已经有了每个用户的基本日期/时间,您只需查找在该用户最后一次请求某些内容之后出现的那些记录(因此需要后续操作)。
然后,要准备用户表中的新列,只需更新每个用户的max(request.date\u time)。
如果一个人在11月27日前是活跃的,并且在那之后有5个对3种不同事件类型的响应,那么你仍然可以在每个11月27日得到这个人,但是其他人可能有更新或更老的“latestrequest”日期。
只是一个可选的想法。。

zdwk9cvp

zdwk9cvp2#

看看这是否得到了正确的答案:

SELECT  COUNT(DISTINCT(e.date_time),
        e.user_id, e.type
    FROM  events e
    JOIN  requests r  ON  e.user_id = r.user_id
                     AND  e.type IN( 3, 5, 6 )
    GROUP BY  e.user_id, e.type
    HAVING  MAX(r.date_time) < e.event_time

索引:

e:  INDEX(type)   -- may be useful (depends on cardinality)
r:  INDEX(user_id, date_time)  -- in this order
qvtsj1bj

qvtsj1bj3#

http://sqlfiddle.com/#!9/c73878/1号

ALTER TABLE `events` ADD INDEX e_type (type);
ALTER TABLE `events` ADD INDEX user_time (user_id, date_time);
ALTER TABLE requests ADD INDEX user_time (user_id, date_time);

SELECT  COUNT(*),
        e.user_id, 
        e.type
FROM `events` e 
JOIN  (
  SELECT user_id, Max(r.date_time) last_seen
  FROM requests r 
  GROUP BY user_id
) r
ON e.user_id = r.user_id 
   AND e.date_time > r.last_seen
WHERE e.type IN( 3, 5, 6 ) 
GROUP  BY e.user_id,  
       e.type
oyxsuwqo

oyxsuwqo4#

我会这样重写查询:

select user_id, type, count(*)
from (select e.user_id, e.type, e.date_time, 
             (select max(r.date_time)
              from requests r
              where r.user_id = e.user_id
              ) as last_seen 
       from events e 
       where e.type  in ( 3, 5, 6 ) 
      ) er
where last_seen < date_time
group by user_id, type;

然后,我要确保在 requests(user_id, date_time) 以及 events(type, user_id, date_time) .

相关问题