2012-12-05 110 views
4

此查询的执行时间超过2秒(对于10k行)。有没有可能优化这个查询?MySQL中BETWEEN的执行时间很长

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,差异):

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

表一个

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'中的记录a在'b'表中的时间戳之间。

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

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 
+0

你能解释一下你的表格结构吗?可能包括您的问题中两个表的“SHOW CREATE TABLE”输出。这些表格如何相互关联?我认为主要问题是您的JOIN条件非常复杂,但如果没有这些信息,很难推荐替代方案。 –

+0

thx为你的答案 - 请现在看到我的问题 – ekstro

+0

它不会帮助这个查询显着,但你应该使时间戳列'TIMESTAMP's或'INT UNSIGNED NOT NULL'; 'BIGINT'只是错误的类型。 ID列也应该是'UNSIGNED'。 –

回答

0

以迈克尔的约定修改时间戳列,该查询将产生原始查询的预期结果与“更快的性能“上面的查询:

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 

的原因,原来的查询体验性能限制是,RDBMS被强制执行的b全表扫描由于在ON子句中使用的公式,因此在a中的每一行。

即使“快”查询需要的b全表扫描,生成“临时”表tmp_b它能够使用上a.timestamp_a索引来提取a基于标准的相应值:tmp_b。 timestamp_b_minus AND tmp_b.timestamp_b_plus