Mysql 慢慢地,我的背都断了!
所以,我已经尝试了我能想到的一切,但无法在我的本地服务器上在不到3秒钟的时间内完成此查询。我知道这个问题与或引用所有者id和个人id有关。如果我运行其中一个或另一个,它会立即发生,但与OR一起运行,我似乎无法使其工作-我试图重写代码,但应用程序的设计方式并不容易。有没有一种方法我可以称之为等价物,或者不会花这么长时间?以下是sql:Mysql 慢慢地,我的背都断了!,mysql,performance,Mysql,Performance,所以,我已经尝试了我能想到的一切,但无法在我的本地服务器上在不到3秒钟的时间内完成此查询。我知道这个问题与或引用所有者id和个人id有关。如果我运行其中一个或另一个,它会立即发生,但与OR一起运行,我似乎无法使其工作-我试图重写代码,但应用程序的设计方式并不容易。有没有一种方法我可以称之为等价物,或者不会花这么长时间?以下是sql: SELECT event_types.name as event_type_name,event_types.id as id, count(events.id)
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 |
+----+-------------+-------------+-------+---------------------------------------------------------------------------------------------------------+-------------------------------+---------+-------------------------------------+------+----------------------------------------------+
查询将是一个问题。分解出永远不会执行的条件的正常解决方案是使用UNION ALL,即:
SELECT *
FROM a
WHERE field1 = 1 OR field2 = 2
致:
只要你不买或不介意复制品,这些作品就行。如果您有重复项并且需要将它们排除,您可以使用联合来代替,但它会进行隐式的不同聚合,因此性能会差得多
您还需要对结果进行排序,这也是一个问题
在这种情况下,您最好的方法是更改数据模型,这样它就可以编写性能查询,也就是说,您根本不需要使用OR
一个问题:事件的所有者id和人员id是否可能相同?使用两个子查询,每个子查询执行两个或路径中的一个,然后合并这些子查询以在顶级select中汇总总数,怎么样 类似于:这里的语法并不精确,因为我是从内存开始的: 从中选择bname、id、sumid、sumtime\u sum 选择具有所有者id的大查询 联合选择。。。带有person_id的大查询可以尝试:
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;
以下是一些提示:
使用而不是=
对id使用int值4,而不是字符串“4”
这就是我要尝试的 我会确保“所有者id”和“个人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;
请注意,我没有尝试过这些,这一切都是在我的头顶上。但这正是我首先要尝试的。尝试在两个查询中使用联合将其拆分以加入结果集,一个使用events.owner\u id=161,另一个使用events.person\u id=161
使用filesort和使用temporary也是一个非常糟糕的标志,您可能应该在事件类型.名称上添加索引。事件和事件类型上有哪些索引?同意,在所有相关表上显示CREATE TABLE的输出在这里非常有用。是的,它们可能是相同的-尽管这并不常见。听起来是时候深入挖掘了,并开始重构数据模型了。出于好奇,union是否都能与GROUPBY一起工作?union基本上只是连接查询结果,因此您可以按每个片段分组,甚至可以按一个而不是另一个进行分组。列的数量和类型必须匹配。为什么与!=?只是想澄清一下,还有!=在mysql和大多数其他类型的sql中,它们在语义上是相同的,因此不会给您带来性能上的好处。但是,将“4”改为仅4将提高性能,因为否则mysql必须在每次比较时进行转换,更重要的是,它不能在必须进行值转换时使用索引。
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;