所以,我已经尝试了我能想到的一切,并且无法在本地服务器上在不到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 |
+----+-------------+-------------+-------+---------------------------------------------------------------------------------------------------------+-------------------------------+---------+-------------------------------------+------+----------------------------------------------+
答案 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;
以下是一些提示:
<>
代替!=
int
值4
代替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上添加一个索引。