在MySQL中使用BETWEEN的执行时间很长

时间:2012-12-05 20:57:20

标签: mysql query-optimization

此查询的执行时间超过2秒(对于10k行)。是否可以优化此查询?

SELECT id, MIN(ABS(timestamp_a - timestamp_b))
FROM a 
  INNER JOIN b ON ( timestamp_a  between (timestamp_b - 5 * 60) 
              AND (timestmap_b + 5 * 60) )
GROUP BY id

示例结果(id,timestamp_a,timestamp_b,diff):

1   1349878538  1349878539  1
2   1349878679  1349878539  2
3   1349878724  1349878539  1
5   1349878836  1349878539  1
6   1349878890  1349878641  1

表a

CREATE TABLE `a` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`timestamp_a`  bigint(20) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX `a` (`timestamp_a`) USING BTREE 
)

表b

CREATE TABLE `b` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`timestamp_b`  bigint(20) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX `b` (`timestamp_b`) USING BTREE 
)

两个表之间没有关系 - 我从表'a'中搜索表'b'中时间戳之间的记录。

编辑:简单解决方案(运行速度非常快):

SELECT id, MIN(ABS(timestamp_a - timestamp_b))
FROM (SELECT id, timestamp, (timestamp - 5 * 60) timestamp_a, (timestamp + 5 * 60) timestamp_b) a
INNER JOIN b ON ( timestamp between timestamp_a AND timestamp_b )
GROUP BY id

1 个答案:

答案 0 :(得分:0)

将Michael的约定用于修改后的时间戳列,此查询将生成原始查询的预期结果,并具有上述“更快”查询的性能:

SELECT a.id, MIN(ABS(a.timestamp_a - tmp_b.timestamp_b))
FROM (SELECT id, timestamp_b, (timestamp_b - 5 * 60) timestamp_b_minus, (timestamp_b + 5 * 60) timestamp_b_plus) tmp_b
INNER JOIN a ON ( a.timestamp_a between tmp_b.timestamp_b_minus AND tmp_b.timestamp_b_plus )
GROUP BY a.id

原始查询是体验性能约束的原因是由于ON子句中使用的公式,RDBMS被迫对b中的每一行执行a的全表扫描。

即使“更快”的查询需要b的全表扫描才能生成“临时”表tmp_b,但它能够使用a.timestamp_a上的索引来提取相应的来自a的值基于以下条件: tmp_b.timestamp_b_minus AND tmp_b.timestamp_b_plus