【发布时间】:2012-06-08 13:57:22
【问题描述】:
问题
以下查询需要超过 30 秒才能运行,除非:
- 我删除了排序(查询然后
- 我删除了 distinct 关键字:(查询然后
- 开始删除连接(查询然后
问题
如何让这个查询在 1 秒内运行。必需:如何获得具有相关数据的唯一会议列表,如下面的联接所述,包括某种类型。
相关数据既用于确定是否存在相关字段,也用于执行 GROUP_CONCAT 操作 - 因此需要对同一个预定项目表进行 3 个不同的连接。
提前感谢您的任何帮助和建议!几个小时以来,我一直在努力解决这个问题!
查询
SELECT
DISTINCT( `meetings`.`id` ) AS `meeting_id`,
`meetings`.`uid` AS meeting_uid,
`meetings_SERV`.`id` AS meetings_SERV_id,
`meetings_TRANSP`.`id` AS meetings_TRANSP_id,
`meetings_ACCO`.`id` AS meetings_ACCO_id,
`meetings_BOOKEDITEMS`.`id` AS meetings_BOOKEDITEMS_id
FROM `meetings` AS meetings
LEFT OUTER JOIN `bookeditems` AS `meetings_SERV`
ON `meetings`.`uid` = `meetings_SERV`.`meeting_uid`
AND 'SER' = `meetings_SERV`.`item_type`
LEFT OUTER JOIN `bookeditems` AS `meetings_TRANSP`
ON `meetings`.`uid` = `meetings_TRANSP`.`meeting_uid`
AND 'TRA' = `meetings_TRANSP`.`item_type`
LEFT OUTER JOIN `bookeditems` AS `meetings_ACCO`
ON `meetings`.`uid` = `meetings_ACCO`.`meeting_uid`
AND 'ACC' = `meetings_ACCO`.`item_type`
LEFT OUTER JOIN `bookeditems` AS `meetings_BOOKEDITEMS`
ON `meetings`.`uid` = `meetings_BOOKEDITEMS`.`meeting_uid`
ORDER BY `meetings`.`datetime`
LIMIT 0, 50
表定义
CREATE TABLE IF NOT EXISTS `bookeditems` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`meeting_uid` varchar(256) NOT NULL,
`item_type` varchar(256) NOT NULL,
PRIMARY KEY (`id`),
KEY `meeting_uid` (`meeting_uid`(255)),
KEY `index1` (`meeting_uid`(255),`item_type`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5889 ;
CREATE TABLE IF NOT EXISTS `meetings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` varchar(256) NOT NULL,
`datetime` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`(255)),
KEY `datetime` (`datetime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7487 ;
解释选择的结果
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
-------------------------------------------------------------------------------------------------------------------------------------
1 | SIMPLE | meetings | ALL | NULL | NULL | NULL | NULL | 7483 | Using temporary; Using filesort
1 | SIMPLE | meetings_SERV | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 |
1 | SIMPLE | meetings_TRANSP | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 |
1 | SIMPLE | meetings_ACCO | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 |
1 | SIMPLE | meetings_BOOKEDITEMS | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 |
分析结果
starting 0.000092
checking permissions 0.000003
checking permissions 0.000002
checking permissions 0.000001
checking permissions 0.000001
checking permissions 0.000003
Opening tables 0.000036
System lock 0.000008
init 0.000033
optimizing 0.000005
statistics 0.000035
preparing 0.000019
Creating tmp table 0.000165
executing 0.000004
Copying to tmp table 1.790968
converting HEAP to MyISAM 1.669041
Copying to tmp table on disk 28.32606
Sorting result 0.141737
Sending data 0.000099
end 0.000005
removing tmp table 0.022097
end 0.000014
query end 0.000008
closing tables 0.000017
freeing items 0.000779
logging slow query 0.000004
cleaning up 0.000005
部分解决方案
根据 Eric R. Rath 在下面的帮助,我已经分析了查询,并通过将 max_heap_table_size=256M 和 tmp_table_size=256M 添加到 MySQL 配置中,我已经能够消除执行步骤“将 HEAP 转换为 MyISAM”和“复制到 tmp磁盘上的表”。
虽然这将总执行时间缩短到 2 秒以下,但我仍然不相信这是我能做的一切,如果在查询优化方面有任何其他建议,请告诉我。
按照 max_heap_table_size 和 tmp_table_size 配置进行分析
...
executing 0.000004
Copying to tmp table 1.790968
Sorting result 0.141737
...
【问题讨论】:
-
Order by语句总是会大大降低查询速度。您也可以删除meeting表上的别名,因为使用别名会强制 MySQL 查看表上的所有字段 -
能否也粘贴查询的
explain的输出?即:EXPLAIN SELECT ...。这将帮助我们了解查询执行计划的外观以及使用了哪些索引。 -
尝试在
(item_type, meeting_id)上添加索引 -
你的表是 InnoDB 还是 MyISAM?
-
@ypercube 它已经将其作为索引(我更新了查询,以便 meeting_id 现在是 meeting_uid); InnoDB
标签: mysql performance