MySQL distinct+sort 查询性能问题

标签 mysql performance

问题

以下查询运行时间超过 30 秒,除非:

  • 我删除排序(然后查询 <1 秒)
  • 我删除了 distinct 关键字:(然后查询 <1 秒)
  • 开始删除连接(然后查询 <5 秒)

问题

如何使此查询在 1 秒内运行。必需:如何获得具有相关数据的唯一 session 列表,如下面的连接(包括某种类型)所述。

相关数据用于确定是否存在相关字段以及执行​​ GROUP_CONCAT 操作 - 因此需要对同一个 bookeditems 表进行 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 ;

EXPLAIN SELECT 的结果

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

最佳答案

我觉得index2不需要,可以去掉;它是 index1 的前缀。不过,这不会减少查询时间。

EXPLAIN 输出显示了真正的罪魁祸首:“使用临时文件,使用文件排序”。有时您可以通过让 MySQL 使用用于连接的相同键执行排序来避免这种情况。如果将 index1 更改为 (meeting_id, datetime),它可能会这样做。如果您需要将 item_type 保留在 index1 中,您可以将其添加为索引中的第三列,或者在包含所有值的查询中包含一个 IN() 子句。

关于MySQL distinct+sort 查询性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10950262/

相关文章:

mysql - magento 表 "sales_flat_order"字段 "protect_code"说明

mysql - 推荐的用户信息数据库结构

php - MySQL -> PHP Array -> Json 需要以数组加对象格式输出

jquery - 如果 jQuery 脚本是在所有页面 HTML 之后加载的,那么它们还需要 $(document).ready 吗?

c - 你是素数吗

php - 我正在调试的代码中的函数似乎没有考虑到夏令时的变化

mysql - Category/Flat.php 中的 Magento URL 索引器正在进行 joinLeft 慢速查询导致站点中断

c++ - 如何在 std::vector 中生成对象而不复制?

c - 在 C 中移动数组的最佳方法?

java - 当第二个进程从队列中消费时,RabbitMQ 吞吐量会下降