Как сохранить IP-адрес в mySQL

На этой неделе в офисе у нас начались здоровые дебаты. Мы создаем Db для хранения информации прокси, в большинстве случаев мы разработали схему, за исключением того, как мы должны хранить IP-адреса. Один лагерь хочет использовать 4 маленьких ключа, по одному для каждого октета, а другой хочет использовать 1 большой int, INET_ATON.

Эти таблицы будут огромными, поэтому производительность является ключевой. Я здесь посередине, так как я обычно использую MS SQL и 4 маленьких ints в моем мире. У меня недостаточно опыта с этим типом хранения IP-адресов.

Мы будем использовать скрипты perl и python для доступа к базе данных для дальнейшей нормализации данных в нескольких других таблицах для ведущих участников, интересного трафика и т.д.

Я уверен, что в сообществе есть некоторые, которые сделали что-то похожее на то, что мы делаем, и мне интересно узнать о их опыте и о том, какой маршрут лучше, 1 большой int или 4 небольших интервала для IP-адресов.

EDIT. Одна из наших проблем - пространство, эта база данных будет огромной, как в 500 000 000 записей в день. Поэтому мы пытаемся взвесить проблему пространства вместе с проблемой производительности.

РЕДАКТИРОВАТЬ 2. Некоторые из разговоров перешли к объему данных, которые мы собираемся хранить... это не мой вопрос. Вопрос в том, является ли предпочтительным способом хранения IP-адреса и почему. Как я уже сказал в своих комментариях, мы работаем для большой компании из 50 компаний. Наши файлы журналов содержат данные об использовании наших пользователей. Эти данные, в свою очередь, будут использоваться в контексте безопасности для управления некоторыми показателями и для управления несколькими инструментами безопасности.

Ответ 1

Я бы предложил посмотреть, какие типы запросов вы будете использовать, чтобы решить, какой формат вы принимаете.

Только если вам нужно вытащить или сравнить отдельные октеты, вам придется рассмотреть их разделение на отдельные поля.

В противном случае сохраните его как целое число в 4 байта. Это также дает вам возможность использовать встроенный MySQL INET_ATON() и INET_NTOA().

Производительность и пространство

хранения:

Если вы собираетесь поддерживать только адреса IPv4, то ваш тип данных в MySQL может быть UNSIGNED INT, который использует только 4 байта хранения.

Для хранения отдельных октетов вам нужно будет использовать только теги UNSIGNED TINYINT, а не SMALLINTS, которые будут использовать по 1 байт каждого хранилища.

Оба метода будут использовать аналогичное хранилище, возможно, немного больше для отдельных полей для некоторых издержек.

Дополнительная информация:

Производительность:

Использование одного поля даст гораздо лучшую производительность, это единственное сравнение вместо 4. Вы упомянули, что будете запускать запросы только по всему IP-адресу, поэтому не должно быть необходимости держать октеты отдельно. Использование функций INET_* MySQL будет выполнять преобразование между текстовыми и целочисленными представлениями один раз для сравнения.

Ответ 2

A BIGINT является 8 байтами в MySQL.

Чтобы сохранить адреса IPv4, достаточно UNSINGED INT, который, как я думаю, используется вами.

Я не могу представить себе сценарий, в котором октеты 4 получат больше производительности, чем один INT, а последний гораздо удобнее.

Также обратите внимание, что если вы собираетесь выпускать такие запросы:

SELECT  *
FROM    ips
WHERE   ? BETWEEN start_ip AND end_ip

где start_ip и end_ip являются столбцами в вашей таблице, производительность будет плохой.

Эти запросы используются, чтобы выяснить, находится ли данный IP в пределах диапазона подсети (обычно для его запрета).

Чтобы сделать эти запросы эффективными, вы должны сохранить весь диапазон как объект LineString с индексом SPATIAL на нем и запросить вот так:

SELECT  *
FROM    ips
WHERE   MBRContains(?, ip_range)

Дополнительную информацию о том, как это сделать, см. в этом блоге в моем блоге:

Ответ 3

Используйте PostgreSQL, там собственный тип данных для этого.

Более серьезно, я бы попал в "один 32-битный целочисленный" лагерь. IP-адрес имеет смысл только тогда, когда все четыре октета рассматриваются вместе, поэтому нет причин хранить октеты в отдельных столбцах базы данных. Вы сохранили бы номер телефона, используя три (или более) разных поля?

Ответ 4

Отдельные поля для меня звучат не очень разумно, как разделение zipcode на разделы или номер телефона.

Может быть полезно, если вам нужна определенная информация в разделах, но я не вижу реальной причины не использовать 32-битный int.

Ответ 5

Старый поток, но для удобства читателей, рассмотрите возможность использования ip2long. Это переводит IP в целое число.

По сути, вы будете конвертировать с ip2long при сохранении в БД, а затем конвертировать обратно с long2ip при извлечении из БД. Тип поля в DB будет INT, поэтому вы сэкономите место и получите лучшую производительность по сравнению с хранением ip в виде строки.

Ответ 6

Эффективное преобразование ip в int и int в ip (может быть полезно для вас):  (PERL)

sub ip2dec {
    my @octs = split /\./,shift;
    return ($octs[0] << 24) + ($octs[1] << 16) + ($octs[2] << 8) + $octs[3];
}

sub dec2ip {
    my $number = shift;
    my $first_oct = $number >> 24;
    my $reverse_1_ = $number - ($first_oct << 24);
    my $secon_oct = $reverse_1_ >> 16;
    my $reverse_2_ = $reverse_1_ - ($secon_oct << 16);
    my $third_oct = $reverse_2_ >> 8;
    my $fourt_oct = $reverse_2_ - ($third_oct << 8);
    return "$first_oct.$secon_oct.$third_oct.$fourt_oct";
}