在工作中,我们对具有以下结构的表进行了查询:
ip_from(number), ip_to(number), country, city, state, isp, latitude, longitude.
此表有大约610万行。
要查找给定IP地址的详细信息,我们使用了如下查询:
SELECT *
FROM Ip2location
WHERE
:ip_num BETWEEN ip_from AND ip_to;
在我们的开发数据库中的Oracle 10上,这需要大约17秒的时间来返回一行,具体取决于传入的ip_num
。在我们更强大的实时系统上,它可能需要5-6秒,这仍然太慢了实时做,我们需要通过后台工作选择这个。
不理想,特别是因为我们的实时系统确实需要ip详细信息。
使用的索引类型是跨越ip_from
和ip_to
的标准BTREE索引。我们考虑了许多事情来尝试加快速度,例如range partitioning。我们最终没有应用它,因为它需要Oracle Enterprise。我们还研究了增加表的并发性,但没有明显的效果。
无论如何,当我喝早晨咖啡时,我意识到我认为可以通过运行以下查询来提高性能:(这是来自内存,可能会有一些错误。我们也选择了单个字段而不是所有内容)
SELECT *
FROM ip2location
WHERE
ip_from = (
SELECT max(ip_from)
FROM ip2location
WHERE ip_from <= :ip_num
)
AND
ip_to >= ip_num;
这适用于我们的数据集,因为ip_from
和ip_to
之间没有重叠的范围。
然而,我没有准备好的是第二个查询的速度有多快。我们的开发数据库上的时间从17秒减少到0.007秒。
这对我来说没什么意义。我希望有一些性能提升,但不是那么多。数据库统计数据是否应该已经确定没有重叠并相应地进行优化?还有一种公认的更快捷方式来选择使用范围吗?
我的问题是:为什么即使使用子选择,第二个查询也要快得多?
答案 0 :(得分:7)
而在上一个查询中,必须对整个数据进行表扫描以计算范围界限