对大表中的排序查询的mysql性能改进

时间:2012-11-09 13:14:57

标签: mysql sql

表格结构:

CREATE TABLE `mytable` (
  `id` varchar(8) NOT NULL,
  `event` varchar(32) NOT NULL,
  `event_date` date NOT NULL,
  `event_time` time NOT NULL,
  KEY `id` (`id`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8

此表中的数据如下所示:

 id      | event      | event_date  | event_time
---------+------------+-------------+-------------
ref1     | someevent1 | 2010-01-01  | 01:23:45
ref1     | someevent2 | 2010-01-01  | 02:34:54
ref1     | someevent3 | 2010-01-18  | 01:23:45
ref2     | someevent4 | 2012-10-05  | 22:23:21
ref2     | someevent5 | 2012-11-21  | 11:22:33

该表包含与此类似的约500,000条记录。

我想在这里询问的问题如下:

SELECT     *
FROM       `mytable`
WHERE      `id` = 'ref1'
ORDER BY   event_date DESC,
           event_time DESC
LIMIT      0, 500

EXPLAIN输出如下:

select_type:   SIMPLE
table:         E
type:          ref
possible_keys: id
key:           id
key_len:       27
ref:           const     
rows:          17024 (a common example)
Extra:         Using where; Using filesort

目的: 此查询由网站生成,LIMIT - 值用于页面导航元素,因此,如果用户想要查看较旧的条目,则会将其调整为500, 500,然后1000, 500等等。

由于字段id中的某些项可以设置在很多行中,因此越来越多的行当然会导致查询速度变慢。分析那些缓慢的查询显示我的原因是排序,大多数时候在查询过程中mysql服务器忙于排序数据。对字段event_dateevent_time建立索引并没有太大改变。

示例SHOW PROFILE结果,按持续时间排序:

state          | duration/sec | percentage
---------------|--------------|-----------
Sorting result |     12.00145 |   99.80640
Sending data   |      0.01978 |    0.16449
statistics     |      0.00289 |    0.02403
freeing items  |      0.00028 |    0.00233
...
Total          |     12.02473 |  100.00000

现在的问题是:

在深入研究像sort_buffer_size和其他服务器配置选项之类的mysql变量之前,你能想到改变查询或排序行为的任何方式,这样排序就不再那么大的性能了此查询仍然存在?

我不介意一些开箱即用的想法。

提前谢谢!

3 个答案:

答案 0 :(得分:2)

正如我在评论中写的多列索引(id,evet_date desc,event_time desc)可能会有所帮助。

如果此表快速增长,您应该考虑在应用程序中添加选项,以便用户选择特定日期范围的数据。

示例:第一步始终返回500条记录,但要选择下一条记录,用户应设置数据的日期范围,然后设置分页。

答案 1 :(得分:1)

索引很可能是解决方案;你只需要做对了。请参阅mysql reference page

最有效的方法是在(id, event_date, event_time)上创建一个由三部分组成的索引。您可以在索引中指定event_date desc, event_time desc,但我认为没有必要。

答案 2 :(得分:1)

我首先要做的是sufleR建议的 - 多列索引(id,event_date desc,event_time desc)。

但是,根据http://dev.mysql.com/doc/refman/5.0/en/create-index.html,支持DESC关键字,但实际上并没有做任何事情。这有点痛苦 - 所以尝试一下,看看它是否能提高性能,但可能不会。

如果是这种情况,你可能不得不通过创建一个“sort_column”作弊,并自动递减值(很确定你必须在应用程序层中这样做,我认为你不能在MySQL中减少),并将该列添加到索引。

你最终得到:

id      | event      | event_date  | event_time  | sort_value
---------+------------+-------------+-------------------------
ref1     | someevent1 | 2010-01-01  | 01:23:45   | 0
ref1     | someevent2 | 2010-01-01  | 02:34:54   | -1
ref1     | someevent3 | 2010-01-18  | 01:23:45   | -2
ref2     | someevent4 | 2012-10-05  | 22:23:21   | -3
ref2     | someevent5 | 2012-11-21  | 11:22:33   | -4

和ID和sort_value的索引。

很脏,但唯一的另一个建议是以其他方式减少与where子句匹配的记录数 - 例如,通过更改接口不返回500条记录,但记录给定日期。