4

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

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

依此类推,这样就有超过 500 万条记录。最后一条记录如下所示:

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

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

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

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

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

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

4

4 回答 4

5

我在 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;
于 2012-10-03T00:05:53.393 回答
3

向表中添加复合索引。该索引必须由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 能够使用新索引。

于 2012-10-03T00:07:57.573 回答
2

索引应该可以很好地处理这个查询,即使该值与StartRangeand不匹配EndRange

于 2012-10-02T23:58:42.827 回答
1

索引不会加速此查询。索引可用于 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 的安全值。希望该范围有一些实际的最大可能值可以告诉您这个数字。

于 2012-10-03T00:20:42.363 回答