如何使分组优化?
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:
requests
table -- 将为每个用户请求在其中插入一个新行。因此,最后(最大)决定了用户最后一次在我们网站上线的时间。
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
这是我的查询:
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:
requests
table -- 将为每个用户请求在其中插入一个新行。因此,最后(最大)决定了用户最后一次在我们网站上线的时间。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