1

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

1 回答 1

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             |
+ ------------- +

然而,在上面的查询中,带有别名的子查询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.actionidtypeid = 1但只列出这样的记录,它存在任何具有相同eventidtypeid = 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.actionidtypeid = 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                  |
+ ------------- + ------------------ +

如果上面显示的查询都不符合您的要求,请显示(基于演示中的示例数据)查询应返回的结果 - 这有助于本论坛中的某人构建满足您所有要求的正确查询。

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

于 2013-10-16T20:06:53.013 回答