慢计数查询 - 解释显示temp和filesort

时间:2013-10-15 11:04:04

标签: mysql

有以下查询运行缓慢, 它生成一个带有“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

explain results

存在以下索引

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);

1 个答案:

答案 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>

然后,当我们认识到满足所有期望的正确查询时,我们就可以开始优化它的性能。