我有一张IP地址表和一个我想加入的IP地址范围表(start ip,end ip)。我已经能够通过以下查询来完成这项工作:
SELECT * FROM `ips` i
JOIN `ranges` a
ON NET.SAFE_IP_FROM_STRING(i.ip)
BETWEEN NET.SAFE_IP_FROM_STRING(a.start_ip)
AND NET.SAFE_IP_FROM_STRING(a.end_ip)
我遇到的问题是它的扩展非常糟糕。要为10个IP执行此操作需要大约8秒,100需要30秒,1000需要几分钟。我希望能够为数千万行做到这一点。 (我已经尝试将NET.SAFE_IP_FROM_STRING
的输出写入范围表,但它只会将速度提高大约10%,并且对缩放没有帮助。
范围不重叠,因此对于输入表中的每一行,我希望输出表中有0或1行。 LATERAL JOIN
让我这样做,几乎肯定能加快速度,但我不认为BigQuery会支持它们。有没有其他方法可以使这个查询更快和可扩展?
答案 0 :(得分:4)
在https://cloudplatform.googleblog.com/2014/03/geoip-geolocation-with-google-bigquery.html查看与Felipe的回答有关的文章之后,我能够将一些非常快速且尺度非常好的东西组合在一起。正如Felipe所提到的,诀窍是直接连接前缀(我用/ 16),然后用中间过滤。我正在预处理范围,将大于/ 16的任何东西分成多个块。然后我用这个查询覆盖表,这会添加一些额外的字段:
SELECT *,
NET.SAFE_IP_FROM_STRING(start_ip) AS start_b,
NET.SAFE_IP_FROM_STRING(end_ip) AS end_b,
NET.IP_TRUNC(NET.SAFE_IP_FROM_STRING(start_ip), 16) as prefix
然后,连接查询看起来像这样:
SELECT * FROM `ips` i
JOIN `ranges` a
ON a.prefix = NET.IP_TRUNC(NET.SAFE_IP_FROM_STRING(i.ip), 16)
WHERE NET.SAFE_IP_FROM_STRING(i.ip) BETWEEN a.start_b AND a.end_b
在计费等级1上加入1000万个IP到100万个范围现在不到30秒!
答案 1 :(得分:1)
我在https://stackoverflow.com/a/20156581
上做了类似的事情我需要更新我对#standardSQL的查询,但基本的秘密是生成一个较小的JOIN区域。
如果您可以共享示例数据集,我很乐意提供新的查询。