Зміст

    IPv4 та IPv6 адреси в ClickHouse

    19.11.2025

    ClickHouse надає великий набір функцій для роботи з IP-адресами, що дозволяє зберігати і обробляти мережеві дані прямо в базі, без необхідності вивантажувати їх у зовнішні скрипти.

    IPv4 та IPv6 в одній колонці   

    Якщо IPv4 і IPv6 зберігаються в різних колонках — ніяких проблем не виникає: кожна група функцій працює з “своїм” типом даних. Але в реальних завданнях (наприклад, при зберіганні логів nginx) часто потрібно розміщувати IPv4 і IPv6 в одній колонці. У цьому випадку зазвичай використовують тип IPv6, куди IPv4 записуються у вигляді IPv4-mapped адрес::ffff:x.x.x.x). Тут і з'являється нюанс: функції для IPv4 і IPv6 відрізняються, і виклик потрібної функції доводиться вибирати за умовою.

    Як позбутися префікса ::ffff: у IPv4-адресах

    При зберіганні IPv4 в колонці типу IPv6 вони автоматичні отримують префікс ::ffff:. Якщо потрібно вивести «чистий» IPv4-адресу, необхідно або перетворити її в тип IPv4, або прибрати префікс рядковими функціями. Тому в запитах зазвичай додають умову, що визначає тип адреси:

    SELECT 
      if(
        startsWith(toString(ip), '::ffff:'), 
        toString(toIPv4(ip)), 
        toString(ip)
      )
    FROM nginx_log;

    Виклик функцій для обробки IP-адрес

    ClickHouse використовує сувору типізацію, схожу з C++. Тому при роботі з IP необхідно явно вказувати перетворення.

    Наприклад, функція IPv4CIDRToRange застосовується тільки до даних типу IPv4. Якщо дані зберігаються у вигляді IPv6, але фактично є IPv4-mapped адресами, їх спочатку потрібно привести до IPv4:

    SELECT
      if(
        startsWith(toString(ip), '::ffff:'),
        toString(IPv4CIDRToRange(toIPv4(ip), netbits).1),
        toString(IPv6CIDRToRange(ip, netbits).1)
      ) AS network
    FROM ngnx_log;

    Формат даних, що повертаються

    Функції IPv4CIDRToRange і IPv6CIDRToRange повертають tuple — масив із заздалегідь визначеними типами. Щоб отримати конкретний елемент, використовується точкова нотація:

    IPv6CIDRToRange(ip, netbits).1

    (Наприклад .1 — це перший елемент масиву).

    Проблема з різними типами і приведення до рядка

    Важливо враховувати, що типи всередині повернутих масивів відрізняються: IPv6CIDRToRange повертає IPv6, а IPv4CIDRToRange — IPv4. Якщо спробувати об'єднати їх без приведення типів, ClickHouse видасть помилку:

    Code: 386. DB::Exception: There is no supertype for types IPv6, IPv4 because some of them are numbers and some of them are not

    Щоб уникнути помилки, необхідно привести значення до єдиного типу — зазвичай до рядкового:

    toString(...)

    Так можна коректно об'єднати результати обох функцій в одному запиті.