【问题标题】:Query exceeded resource limits in Bigquery查询超出 Bigquery 中的资源限制
【发布时间】:2018-08-22 07:32:50
【问题描述】:

为了查找特定 IP 地址的国家/地区,我使用了 Maxmind IP 地址数据库。我已经下载了数据库并将其导入到 Google BigQuery 中,所以我可以查询它。在一个单独的表中,我正在从我们系统中的某些事件中捕获 IP 地址。我现在想加入这两个数据源。

Maxmind数据库中的列如下:

  • start_ip_range STRING NULLABLE
  • end_ip_range STRING NULLABLE
  • start_ip_num STRING NULLABLE
  • end_ip_num STRING NULLABLE
  • country_code STRING NULLABLE
  • 国家/地区名称

我的事件表中的列是:

  • request_id STRING NULLABLE
  • ip_address STRING NULLABLE

正如此处 (https://dev.maxmind.com/geoip/legacy/csv/) 所述,有一种方法可以获取 IP 地址的整数表示,因此我可以使用它来查询 IP 地址并检索国家代码或国家名称。

我现在已经构建了以下查询:

SELECT
  p.*,
  g.country_code AS country_code
FROM
  `dev.event_v1` p
INNER JOIN
  `dev.geo_ip_countries` g
ON
  SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(0)] AS NUMERIC)*16777216 + 
  SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(1)] AS NUMERIC)*65536 + 
  SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(2)] AS NUMERIC)*256 + 
  SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(3)] AS NUMERIC)
BETWEEN 
  SAFE_CAST(g.start_ip_num AS INT64)
AND 
  SAFE_CAST(g.end_ip_num AS INT64)
LIMIT 100

然而,这在使用限制时有效,但不适用于构建视图。

两个问题: 1.有没有办法简化查询 2.当我尝试返回一个大的结果集时,Google BigQuery 会抛出一个错误:

Error: Query exceeded resource limits. 28099.974050246612 CPU seconds were used, and this query must use less than 5600.0 CPU seconds.

感谢任何帮助!

解决方案 将查询重写为以下内容也可以解决资源限制问题:

SELECT
  p.*,
  g.country_code
FROM
  `dev.event_v1` p
INNER JOIN
  `dev.geo_ip_countries` g
ON 
  NET.IP_TRUNC(NET.SAFE_IP_FROM_STRING(p.ip_address),16) = NET.IP_TRUNC(NET.SAFE_IP_FROM_STRING(g.start_ip_range),16)
WHERE 
  NET.SAFE_IP_FROM_STRING(p.ip_address) 
  BETWEEN 
    NET.SAFE_IP_FROM_STRING(g.start_ip_range) 
  AND 
    NET.SAFE_IP_FROM_STRING(g.end_ip_range)

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    试试下面(BigQuery 标准 SQL)

    #standardSQL
    SELECT
      p.* EXCEPT(ip_address_num),
      g.country_code AS country_code
    FROM (
      SELECT *, 
        SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(0)] AS NUMERIC)*16777216 + 
        SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(1)] AS NUMERIC)*65536 + 
        SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(2)] AS NUMERIC)*256 + 
        SAFE_CAST(SPLIT(p.ip_address, ".")[OFFSET(3)] AS NUMERIC) ip_address_num
      FROM `dev.event_v1` 
    ) p
    INNER JOIN (
      SELECT 
        SAFE_CAST(g.start_ip_num AS INT64) start_ip_num, 
        SAFE_CAST(g.end_ip_num AS INT64) end_ip_num,
        country_code
      FROM `dev.geo_ip_countries`
    ) g
    ON ip_address_num BETWEEN g.start_ip_num AND g.end_ip_num
    

    【讨论】:

    • 不幸的是,以上并没有解决我遇到的繁重的计算问题。查询的大部分处理实际上是在计算ip地址的数值时完成的。现在已经使用了 BigQuery 的 NET 函数(来自接受的答案)。非常感谢!
    【解决方案2】:

    因此,您将dev.event_v1 中的所有内容与dev.geo_ip_countries 结合起来,以获得dev.geo_ip_countries.country_codedev.event_v1 中每一行的dev.geo_ip_countries.country_code。我想你会对左连接感兴趣。

    您可能有兴趣测试net functions 中的转换是否可以替换您的数学部分。

    我对可能划分它的 event_v1 请求或 ip_addresses 的内容知之甚少,但我敢打赌那里的行数比 geo_ip_countries 中的行数要多得多。这可能是您查询时间的大部分。假设您需要将时间减少约 6 倍。您可能应该选择其中的第 6 个来加入并插入到临时表中,然后依次重复接下来的第 6 个。

    我认为使用NTILE(6) 会对您有所帮助;也许OVER (ROWS UNBOUNDED PRECEDING) as nt,真的不确定。然后在 where 或 join on 子句中使用 nt = 1

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多