Как сохранить IP в mySQL - PullRequest
24 голосов
/ 10 июля 2009

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

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

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

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

РЕДАКТИРОВАТЬ - Одна из наших проблем - это пространство, эта база данных будет огромной, как 500 000 000 записей в день. Таким образом, мы пытаемся взвесить проблему пространства вместе с проблемой производительности.

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

Ответы [ 5 ]

24 голосов
/ 10 июля 2009

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

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

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

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

Хранение:

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

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

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

Подробнее:

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

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

13 голосов
/ 10 июля 2009

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 голосов
/ 10 июля 2009

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

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

1 голос
/ 10 июля 2009

Отдельные поля для меня не кажутся особенно разумными - очень похоже на разделение почтового индекса на секции или номер телефона.

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

0 голосов
/ 10 июля 2009

Эффективное преобразование 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";
}
...