我正在运行一个MySQL服务器(5.5),它有一个大表(大约有10M记录)。此表是某种日志,其中包含2列主键:
id <- integer,
date <- datetime
连接到此数据库的应用程序正在发送一个类似以下内容的查询:
SELECT * FROM bigtable
INNER JOIN other_table
ON ....
WHERE UNIX_TIMESTAMP(date) BETWEEN #somevalue# AND #somevalue2#;
我发现这个查询花了很多时间来执行。我知道有些函数可以阻止MySQL使用索引并使其执行全表扫描。
问题: 如图所示,通过在主键的列上使用UNIX_TIMESTAMP功能而不是 “... WHERE date BETWEEN'2012:01:01 00:00:00'AND'2012: 02:01 00:00:00'“ ?
查询:
SELECT r.f_registro, r.latitud, r.longitud, r.velocidad, r.status, r.odometro, r.heading, r.sensor, a.nombre FROM registros r INNER JOIN activos a ON a.id_tracker = r.id_tracker WHERE a.id_activo = 2366 AND r.satelites > '3' AND UNIX_TIMESTAMP(r.f_registro) BETWEEN 1342159200 AND 1342760400 ORDER BY r.f_registro
执行需要几秒甚至几分钟! 运行说明返回:
id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,SIMPLE,a,const,PRIMARY,PRIMARY,4,const,1,"Using filesort"
1,SIMPLE,r,range,"id_tracker,satelites",satelites,4,NULL,1,"Using index condition; Using where"
答案 0 :(得分:6)
使用日期列上的函数可以防止MySQL使用列上的索引。
相反,将范围计算为两个日期常量并使用BETWEEN。
另请注意,您没有表明日期列上有索引。索引保留最多前缀,因此以id开头的复合索引不能用于仅请求日期的查询。
查询的ON部分(您已排除)可能在查询性能中同样重要,您应该评估是否也能使用索引。
答案 1 :(得分:5)
如果您的日期范围必须是UNIX时间,则可以更改:
UNIX_TIMESTAMP(r.f_registro) BETWEEN 1342159200 AND 1342760400
为:
r.f_registro BETWEEN FROM_UNIXTIME(1342159200) AND FROM_UNIXTIME(1342760400)
这将大大加快查询速度。在我的情况下(有3.8亿行和索引日期的列),这表示从小时到毫秒的变化。