慢MySQL查询打破我的背!

时间:2010-01-18 23:57:12

标签: mysql performance

所以,我已经尝试了我能想到的一切,并且无法在本地服务器上在不到3秒的时间内完成此查询。我知道问题与OR引用owner_id和person_id有关。如果我运行一个或另一个它立即发生,但与一个或我似乎无法使其工作 - 我考虑重写代码,但应用程序的设计方式并不容易。有没有办法可以称之为等价物,或者不会花那么长时间?这是sql:

SELECT event_types.name as event_type_name,event_types.id as id, count(events.id) as 
count,sum(events.estimated_duration) as time_sum FROM events,event_types 
WHERE event_types.id = events.event_type_id AND events.event_type_id != '4' 
AND ( events.status!='cancelled') 
AND events.event_type_id != 64 
AND ( events.owner_id = 161 OR events.person_id = 161 ) 
GROUP BY event_types.name 
ORDER BY event_types.name DESC;

这是解释汤,虽然我猜这是不必要的,因为可能有更好的方法来构建那个或那个显而易见的:

非常感谢!克里斯。

+----+-------------+-------------+-------+---------------------------------------------------------------------------------------------------------+-------------------------------+---------+-------------------------------------+------+----------------------------------------------+
| id | select_type | table       | type  | possible_keys                                                                                           | key                           | key_len | ref                                 | rows | Extra                                        |
+----+-------------+-------------+-------+---------------------------------------------------------------------------------------------------------+-------------------------------+--
|  1 | SIMPLE      | event_types | range | PRIMARY                                                                                                 | PRIMARY                       | 4       | NULL                                |   78 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | events      | ref   | index_events_on_status,index_events_on_event_type_id,index_events_on_person_id,index_events_on_owner_id | index_events_on_event_type_id | 5       | thenumber_production.event_types.id |  907 | Using where                                  |
+----+-------------+-------------+-------+---------------------------------------------------------------------------------------------------------+-------------------------------+---------+-------------------------------------+------+----------------------------------------------+

5 个答案:

答案 0 :(得分:0)

查询将成为一个问题。分解OR条件(永远不会有效)的正常解决方案是使用UNION ALL,即:

SELECT *
FROM a
WHERE field1 = 1 OR field2 = 2

为:

SELECT *
FROM a
WHERE field1 = 1
UNION ALL
SELECT *
FROM a
WHERE field2 = 2

只要你没有(或不介意)重复这些作品。如果你有重复项并且需要将它们分解出来,你可以使用UNION,但是这会进行隐式DISTINCT聚合,因此性能会低得多。

此外,您还要对结果进行排序,这也将是一个问题。

这是一种最好的方法是更改​​数据模型,以便编写高性能查询(即所以你根本不需要使用OR)。

一个问题:事件的owner_id和person_id是否可以相同?

答案 1 :(得分:0)

如何使用两个子查询,每个子查询执行两个“或”路径之一,并将这些子查询联合起来总结顶级选择中的总数?

类似的东西:(这里的语法并不精确,因为我要从记忆中走出来):

选择(bname,id,sum(id),sum(time_sum)from ((选择...与owner_id的大查询) union(选择...与person_id的大查询))

答案 2 :(得分:0)

也许试试:

   SELECT event_types.name AS event_type_name, event_types.id AS id,
          COUNT(events.id) AS count, SUM(events.estimated_duration) AS time_sum
     FROM events
     JOIN event_types ON event_types.id = event.event_type_id
    WHERE events.event_type_id <> 4
      AND events.status <> 'cancelled'
      AND events.event_type_id <> 64 
      AND ( events.owner_id = 161 OR events.person_id = 161 ) 
 GROUP BY event_types.id 
 ORDER BY event_types.name DESC;

以下是一些提示:

  • 使用<>代替!=
  • 使用int4代替string '4'

答案 3 :(得分:0)

这就是我想要的。

我会确保'owner_id'和'person_id'都有唯一的密钥:

alter table events add unique (person_id, id), add unique (owner_id, id);

你还应该定期运行:

analyze table events;

试一试。

另一个选择是尝试将查询的坏部分移动到连接谓词中。

SELECT event_types.name as event_type_name,event_types.id as id, count(events.id) as 
count,sum(events.estimated_duration) as time_sum FROM events,event_types
JOIN event_types on event_types.id = events.event_type_id
AND ( events.owner_id = 161 OR events.person_id = 161 )
WHERE events.event_type_id != '4' 
AND ( events.status!='cancelled') 
AND events.event_type_id != 64 
GROUP BY event_types.name 
ORDER BY event_types.name DESC;

请注意,我还没有尝试过任何一项,而且这一切都是我的头脑。但它我会先尝试的。

答案 4 :(得分:0)

尝试使用UNION在2个查询中将其分解以加入结果集,一个使用events.owner_id = 161,另一个使用events.person_id = 161.

“使用filesort,使用临时”也是一个非常糟糕的标志,你应该在event_types.names上添加一个索引。