Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/87.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何加速使用中间条件的SQL查询?_Mysql_Sql_Optimization - Fatal编程技术网

Mysql 如何加速使用中间条件的SQL查询?

Mysql 如何加速使用中间条件的SQL查询?,mysql,sql,optimization,Mysql,Sql,Optimization,我有一张这样的桌子: ID StartRange EndRange ---------------------------- 1 1 3 2 4 8 3 9 12 ID StartRange EndRange --------------------------------- 5235976 9894727374 9894727378 等等等

我有一张这样的桌子:

ID    StartRange    EndRange
----------------------------
 1        1            3
 2        4            8
 3        9           12
ID        StartRange    EndRange
---------------------------------
5235976   9894727374   9894727378
等等等等,所以有超过500万条记录。最后一条记录如下所示:

ID    StartRange    EndRange
----------------------------
 1        1            3
 2        4            8
 3        9           12
ID        StartRange    EndRange
---------------------------------
5235976   9894727374   9894727378
换句话说,每个记录的起始和结束范围永远不会重叠

我需要执行一个查询,查找与范围匹配的数字的对应ID:

SELECT ID FROM BigTable WHERE '5000000' BETWEEN StartRange AND EndRange;
不幸的是,此查询需要几秒钟才能完成。我需要对它进行优化,以使它花费最少的执行时间。我做了一点研究,似乎添加索引没有什么帮助,因为它只适用于数字正好是StartRange或EndRange值的情况,而不适用于介于两者之间的情况


有没有人有我可以用来缩短执行时间的技巧?理想情况下,如果可能的话,我希望它不超过1秒。

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

我在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;

向表中添加复合索引。此索引必须由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'

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

索引不会加速此查询。索引可以用于两次搜索之间,但只有当它们在10000到20000之间时才是正确的

为了加快查询速度,您必须使用一些技巧

首先,如果范围表是静态的或增长不快,并且范围值实际上是整数,则可以生成一个额外的表,其中包含从最低起始值到最高结束值的所有值以及匹配的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的安全值。希望这个范围有一些实际的最大可能值可以告诉您这个数字。

您当前的表模式是什么?SHOW CREATE TABLE your_TABLE的输出您还可以发布BigTable中descripe SELECT ID的输出,其中StartRange和EndRange之间的“5000000”?这将显示是否正在使用索引。当然,输出是这样的:1个简单的BigTable ALL ID,StartRange,EndRange 5522123,使用where,如果您创建@Jocelyn的答案中描述的索引,您会得到相同的结果,还是现在使用键?我运行了一个小测试用例,密钥确实是根据explain使用的。我刚刚尝试过,explain的输出是相同的。我同意。这应该会大大加快速度。我在StartRange和EndRange中添加了一个索引,但似乎没有任何速度改进,一个简单的查询大约需要10秒。然后请按照Jocelyn和willoller的建议执行,这样我们就可以调试了。+1有趣。。。您是否碰巧有一个很好的资源来深入讨论这个案例?似乎有时会使用索引,但只使用第一部分,在最坏的情况下,它最终会查看每一行?还是别的?谢谢你的回答,拉里。我们将进行调查,看看这是否对我们有帮助。第一种方法可能不实用,因为它将创建一个包含90多亿行的表,这肯定会有很多行。顺便说一句,SQL可能不是解决这个问题的最佳方法。你考虑过类似于二进制搜索的东西吗?您可以从表中进行搜索,或者根据环境的不同,为这个特定的搜索维护一个内存结构。我来这里是为了寻找一种从GeoLite搜索ip地址范围的快速方法。这个答案将查找速度提高了10倍。谢谢