有以下查询运行缓慢, 它生成一个带有“action.typeid = 1”的ACTION记录列表 如果存在“typeid = 2”的ACTION记录,也会计数。 这是一个减慢事情的计数 - 它使用临时和文件输出! 你能帮我找到改进方法吗?
EXPLAIN
SELECT
action.actionid
FROM
ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
LEFT JOIN
(SELECT
COUNT(1),
action.eventid
FROM
ACTION
WHERE (action.typeid = '2')
GROUP BY action.eventid) AS act
ON act.eventid = event.eventid
WHERE actiondate2 BETWEEN 20130601
AND 20131031
AND event.siteid = 1
AND action.typeid = 1
存在以下索引
CREATE INDEX idx_cusid ON `event` (cusid);
CREATE INDEX idx_actiontypeid ON `action` (typeid);
CREATE INDEX idx_actioneventid ON `action` (eventid);
CREATE INDEX idx_actiondate ON `action` (actiondate2);
CREATE INDEX idx_eventsiteid ON `event` (siteid);
答案 0 :(得分:1)
我将用例子来解释我的困惑。
请看一个简单的演示:http://sqlfiddle.com/#!2/19f52c/6
此演示包含一个简化的(为了清晰起见)数据库结构和查询。
来自问题的查询(演示中的第一个查询)返回以下结果:
SELECT action.actionid
FROM ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
LEFT JOIN
(SELECT
COUNT(1),
action.eventid
FROM
ACTION
WHERE (action.typeid = '2')
GROUP BY action.eventid) AS act
ON act.eventid = event.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
| 5 |
+ ------------- +
Hovever,在上面的查询中,带有别名ACT
的子查询只是......没用。
查询执行此子查询(消耗时间和服务器资源),然后...忽略其结果,只是抛弃它们。
上面的查询等同于下面的查询(演示中的第二个查询) - 它返回与问题中的查询相同的结果,但不使用子查询(节省时间和资源,因此会更好地执行):
SELECT action.actionid
FROM
ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
| 5 |
+ ------------- +
如果您的意图是以优化问题中的查询显示 - 那么请使用上面显示的查询,这是您问题的答案。
但是,看一下您对预期结果的评论,似乎问题中的查询可能是错误的 - 它没有给出预期结果。
嗯,但目前还不清楚查询应该提供什么?有很多可能性,我将在下面展示其中一些。
如果您需要使用action.actionid
列出所有typeid = 1
,但只列出存在的任何记录eventid
和{{ 1}} ...然后使用以下查询(演示中的第3个查询):
typeid = 2
此查询使用SELECT a.actionid
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
EXISTS ( SELECT 1 FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
)
AND e.siteid = 1
AND a.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
+ ------------- +
运算符,而不是EXISTS
- 如果我们想要存在相同记录的信息,我们不需要计算所有这些!计数必须读取所有记录,如果COUNT()
找到满足条件的第一条记录,则EXISTS
会停止读取表格 - 因此EXISTS
通常比COUNT()
更快。
如果您需要使用action.actionid
列出所有typeid = 1
,并且还显示typeid = 2
存在某些相应记录的信息,请使用以下查询(演示中的第四个查询) ):
SELECT
a.actionid ,
CASE WHEN EXISTS ( SELECT 1 FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
)
THEN 'typeid=2 EXISTS'
ELSE 'typeid=2 DOESN''T EXIST'
END typeid2_exist
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
e.siteid = 1
AND a.typeid = 1
;
+ ------------- + ---------------------- +
| actionid | typeid2_exist |
+ ------------- + ---------------------- +
| 1 | typeid=2 EXISTS |
| 3 | typeid=2 EXISTS |
| 5 | typeid=2 DOESN'T EXIST |
+ ------------- + ---------------------- +
但是如果你真的需要用typeid = 2
计算相应的记录 - 那么这个查询可以提供帮助(演示中的第五个查询):
SELECT
a.actionid ,
( SELECT count(*) FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
) typeid2_count
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
e.siteid = 1
AND a.typeid = 1
;
+ ------------- + ------------------ +
| actionid | typeid2_count |
+ ------------- + ------------------ +
| 1 | 1 |
| 3 | 1 |
| 5 | 0 |
+ ------------- + ------------------ +
如果上面显示的查询都不符合您的要求,请显示(基于演示中的示例数据)查询应返回的结果 - 这有助于此论坛中的某人构建满足您所有要求的正确查询。 / p>
然后,当我们认识到满足所有期望的正确查询时,我们就可以开始优化它的性能。