如何使分组优化?

How can I make grouping optimize?

这是我的查询:

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:

看到了吗?非常理想。所以问题在这里分组。知道如何改进该查询吗?


编辑: 我们需要两个 tables:

  1. requests table -- 将为每个用户请求在其中插入一个新行。因此,最后(最大)决定了用户最后一次在我们网站上线的时间。

  2. events table -- 每个答案、评论都会在其中插入一个新行。

我们谈论的是 Q/A 网站。我们要做的就是 "sending an email to the users who got a new comment/answer after their last time being online in our website".

您的 table 需要适当的索引来匹配 WHERE 子句和排序依据以帮助优化。

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" 是基于您的主要 table 查询,与请求 table 的实际 JOIN 无关。联接应代表实际列以符合 table 之间的条件。

建议 post 编辑问题。我可能会提供另一种选择。为 "lastRequest" date/time 字段的用户 table 添加一列。然后,每当为该用户输入请求时,更新用户 table 中的字段。您不需要保留子查询 max() 来找出何时。这可能会将您的查询简化为...随着您的请求 table 变大,您的查询时间也会变大。通过直接查看用户 table 一次已知的最新请求,您就有了答案。查询 1 万个用户,或 200 万个请求...您的选择:)

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

所以您的加入已经有每个用户的基础 date/time,您可以只查找在该人最后一次请求某事之后出现的那些记录(因此跟进)。

然后,要在您的用户 table 中准备新列,您只需更新每个用户的最大值 ( request.date_time )。

如果一个人在 ex: 11 月 27 日之前是活跃的,并且在那之后对 3 种不同的事件类型有 5 个响应,你仍然会根据他们 11 月 27 日的日期得到那个人,但其他人可能有更新或更旧的 "latestRequest" 日期。

只是一个可选的想法..

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 

我会这样重写查询:

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) 上是否有索引。

看看这是否得到 'right' 个答案:

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