表格结构:
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_date
和event_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变量之前,你能想到改变查询或排序行为的任何方式,这样排序就不再那么大的性能了此查询仍然存在?
我不介意一些开箱即用的想法。
提前谢谢!
答案 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条记录,但记录给定日期。