如何加快使用BETWEEN条件的SQL查询?

时间:2012-10-02 23:55:56

标签: mysql sql optimization

我有一个看起来像这样的表:

ID    StartRange    EndRange
----------------------------
 1        1            3
 2        4            8
 3        9           12

依此类推,以便有超过500万条记录。最后一条记录看起来像这样:

ID        StartRange    EndRange
---------------------------------
5235976   9894727374   9894727378

换句话说,StartRangeEndRange永远不会为每条记录重叠。

我需要进行查询,找到与范围匹配的数字的相应ID:

SELECT ID FROM BigTable WHERE '5000000' BETWEEN StartRange AND EndRange;

不幸的是,此查询需要几秒钟才能完成。我需要对其进行优化,以便花费最少的执行时间。我做了一些研究,看起来添加一个索引没有帮助,因为它只适用于数字恰好是StartRangeEndRange值的情况,但如果它在两者之间则不适用。

有没有人可以使用任何提示或技巧来降低执行时间?理想情况下,如果可能,我希望它低于1秒。

4 个答案:

答案 0 :(得分:4)

向表中添加复合索引。此索引必须由StartRangeEndRange字段组成:

ALTER TABLE `BigTable` ADD INDEX ( `StartRange` , `EndRange` );

然后在查询中使用EXPLAIN来检查是否使用了新索引:

EXPLAIN SELECT ID FROM BigTable WHERE '5000000' BETWEEN StartRange AND EndRange;

输出显示MySQL无法在此查询中使用新索引。然后,您可以重写初始查询:

SELECT ID FROM BigTable WHERE StartRange>='5000000' AND EndRange<='5000000'
                            OR EndRange>='5000000' AND StartRange<='5000000'

此新查询将返回与初始查询相同的结果。好消息是EXPLAIN

EXPLAIN SELECT ID FROM BigTable WHERE StartRange>='5000000' AND EndRange<='5000000'
                            OR EndRange>='5000000' AND StartRange<='5000000'

输出现在显示MySQL能够使用新索引。

答案 1 :(得分:3)

我遇到了一个类似ip地址范围表的问题,下面真的为我做了诀窍。你至少需要一个至少StartRange的索引。

SELECT ID
FROM BigTable
INNER JOIN
  (SELECT MAX(StartRange) AS start
   FROM BigTable
   WHERE StartRange <= @Target) AS s
ON StartRange = s.start
WHERE EndRange >= @Target;

答案 2 :(得分:2)

索引应该很好地处理此查询,即使该值与StartRangeEndRange不匹配。

答案 3 :(得分:2)

索引不会加速此查询。索引可以用于BETWEEN搜索,但只有乳清才能“正确”(例如StartRange BETWEEN 10000 AND 20000)。

为了加快这个问题,你将不得不采取一些技巧。

首先,如果范围表是静态的或者没有快速增长,并且范围值实际上是整数,则可以生成一个额外的表,其中包含从最低StartRange到最高EndRange以及匹配id的所有值。然后,您可以搜索所需的确切值。

或者,计算EndRange的最大值 - StartRange并将其命名为MaxRange。在StartRange上创建索引并将查询更改为:

 SELECT ID FROM BigTable 
    WHERE StartRange BETWEEN ('5000000' - MaxRange) AND '5000000' 
      AND '5000000' BETWEEN StartRange AND EndRange;

现在,第一个BETWEEN子句可索引的,应返回少量行。然后,第二个BETWEEN子句将仅应用于该行的小子集。显然,这取决于您能够提前计算MaxRange的安全值。希望这个范围有一些实际的最大可能值,告诉你这个数字。