【发布时间】:2020-05-19 08:47:37
【问题描述】:
我有一个请求列表及其各自的 IP 地址(约 200 万行)。我正在尝试在 non-overlapping 和 complete 的 IP 范围列表(约 1200 万行)列表上做一个简单的 JOIN。我已经用ip_from b_tree 升序和ip_to b_tree 升序索引了IP范围。
我尝试了几种技术来管理这两个表中的数据,但到目前为止都证明效率很低。
我尝试了常规的JOIN、JOIN,IP 范围为maximum difference,并使用了子查询。使用EXPLAIN,他们都显示有possible_keys,但没有使用它们。我试过使用FORCE INDEX 没有任何运气。
Regular select 分别显示SELECT * FROM ip_ranges WHERE INET_ATON(<some ip>) <= ip_to LIMIT 1; 的 IP 查找大约需要 2 毫秒,而请求表每 200 次查找大约需要 16 毫秒。
这是我当前的查询。仅仅因为索引没有被充分利用,这需要大约 30 秒才能返回任何结果:
SELECT
rs.fingerprint,
rs.ip,
ipr.country_code,
ipr.country_name,
ipr.region,
ipr.city,
ipr.isp_name,
ipr.domain_name,
ipr.usage_type
FROM requests AS rs
JOIN ip_ranges AS ipr ON INET_ATON(rs.ip) BETWEEN ipr.ip_from AND ipr.ip_to
LIMIT 10;
那么,有什么方法可以针对 MySQL 进行优化吗?还是我应该只使用 Python 为每个请求单独调用数据库? (在 SQL 之外手动加入它们)。
更新:
我现在尝试将每个 IP 地址转换为它们各自的数字格式,存储在名为 ip_numeric 的 DECIMAL(39) 列中,如下面的答案中所建议的那样。 39 也用于支持 IPv6 地址。数据库仍然不会使用索引键进行范围查找。
【问题讨论】:
-
@TheImpaler 您能否详细说明“左侧综合征”。
rs.ip是一个 IP 地址,我需要数字版本来加入范围。 -
一种优化方法是存储和索引 aton 值(或 ntoa 值)。顺便说一句,没有 ORDER BY 的 LIMIT 没有多大意义。
-
如果没有
ORDER BY,您会从LIMIT获得一组不可预测的10 行;这是你所期望的吗?还是您打算对所有 2M 行执行此查询? -
@RickJames 是的,我使用限制 10 只是为了避免必须查询所有 2M 行以进行基准测试。
-
@CompSci - 请注意,根据优化机会,这 3 种情况的行为可能会有很大不同:1) 只是 LIMIT,2) ORDER BY + LIMIT,3) 两者都不是。要获得“真实”的答案,您需要提出“真实”的问题。
标签: mysql sql ip query-optimization