子查询中使用的内存和执行顺序

时间:2018-08-06 10:09:21

标签: clickhouse

我正在处理https://dev.maxmind.com/geoip/geoip2/geolite2/中csv格式的数据。 通常,是从ip块映射到asn和国家/地区的数据。

我有2个表,它们都是Memory引擎,第一个有299727条记录,第二个有406685条记录。

SELECT *
FROM __ip_block_to_country 
LIMIT 5

┌─network────┬───────id─┬───min_ip─┬───max_ip─┬─geoname_id─┬─country_iso_code─┬─country_name─┐
│ 1.0.0.0/24 │ 16777216 │ 16777217 │ 16777472 │    2077456 │ AU               │ Australia    │
│ 1.0.1.0/24 │ 16777472 │ 16777473 │ 16777728 │    1814991 │ CN               │ China        │
│ 1.0.2.0/23 │ 16777728 │ 16777729 │ 16778240 │    1814991 │ CN               │ China        │
│ 1.0.4.0/22 │ 16778240 │ 16778241 │ 16779264 │    2077456 │ AU               │ Australia    │
│ 1.0.8.0/21 │ 16779264 │ 16779265 │ 16781312 │    1814991 │ CN               │ China        │
└────────────┴──────────┴──────────┴──────────┴────────────┴──────────────────┴──────────────┘

SELECT *
FROM __ip_block_to_asn 
LIMIT 5

┌─network──────┬─autonomous_system_number─┬─autonomous_system_organization─┬───────id─┬─subnet_count─┬───min_ip─┬───max_ip─┐
│ 1.0.0.0/24   │                    13335 │ Cloudflare Inc                 │ 16777216 │          255 │ 16777217 │ 16777472 │
│ 1.0.4.0/22   │                    56203 │ Gtelecom-AUSTRALIA             │ 16778240 │         1023 │ 16778241 │ 16779264 │
│ 1.0.16.0/24  │                     2519 │ ARTERIA Networks Corporation   │ 16781312 │          255 │ 16781313 │ 16781568 │
│ 1.0.64.0/18  │                    18144 │ Energia Communications,Inc.    │ 16793600 │        16383 │ 16793601 │ 16809984 │
│ 1.0.128.0/17 │                    23969 │ TOT Public Company Limited     │ 16809984 │        32767 │ 16809985 │ 16842752 │
└──────────────┴──────────────────────────┴────────────────────────────────┴──────────┴──────────────┴──────────┴──────────┘

现在,我想检查哪个国家涵盖一个asn的整个IP池。以下查询仅用于获取法定国家/地区的索引。

SELECT idx from(
SELECT 
    (
        SELECT groupArray(min_ip),groupArray(max_ip),groupArray(country_iso_code),groupArray(country_name)
        FROM __ip_block_to_country
    ) t,
    arrayFilter((i,mii, mai) -> min_ip >= mii and max_ip <= mai, arrayEnumerate(t.1), t.1, t.2) as idx
FROM __ip_block_to_asn
);

我遇到以下异常: Received exception from server (version 1.1.54394): Code: 241. DB::Exception: Received from localhost:9000, ::1. DB::Exception: Memory limit (for query) exceeded: would use 512.02 GiB (attempt to allocate chunk of 549755813888 bytes), maximum: 37.25 GiB.

我的问题是:

  • 似乎语句SELECT groupArray(min_ip),groupArray(max_ip),groupArray(country_iso_code),groupArray(country_name)__ip_block_to_asn的每条记录一起执行,因此查询需要这么多的内存。这对我的查询是否正确?

1 个答案:

答案 0 :(得分:3)

标量子查询仅执行一次。

但是要执行arrayFilter,将数组乘以__ip_block_to_asn表中已处理块的行数。就像两个表的交叉连接一样。

要解决此问题,可以对__ip_block_to_asn中的SELECT使用较小的块大小。 它由max_block_size设置控制。但是对于Memory表,无论SELECT期间的max_block_size设置如何,块总是具有与插入表时相同的大小。要允许灵活的块大小,可以将该表重新加载到TinyLog引擎中。

CREATE TABLE __ip_block_to_asn2 ENGINE = TinyLog AS SELECT * FROM __ip_block_to_asn

然后执行:

SET max_block_size = 10;

SELECT idx from(
SELECT 
(
    SELECT groupArray(min_ip),groupArray(max_ip),groupArray(country_iso_code),groupArray(country_name)
    FROM __ip_block_to_country
) t,
arrayFilter((i,mii, mai) -> min_ip >= mii and max_ip <= mai, arrayEnumerate(t.1), t.1, t.2) as idx
FROM __ip_block_to_asn2
);