如何在mySQL中存储IP

时间:2009-07-10 10:58:43

标签: python mysql perl ip-address

本周我们在办公室里进行了一场健康的辩论。我们正在创建一个Db来存储代理信息,因为除了我们应该如何存储IP之外,我们大部分都已经制定了模式。一个阵营想要使用4个小点,一个用于每个八位位组,另一个想要使用一个大的int,INET_ATON。

这些表格将是巨大的,因此性能是关键。我在这里中间,因为我通常在我的世界中使用MS SQL和4个小的int。我对这种类型的卷存储IP没有足够的经验。

我们将使用perl和python脚本来访问数据库,以进一步将数据标准化为其他几个表格,用于高级谈话者,有趣的流量等。

我确信社区中有一些人已经做了与我们正在做的事情类似的事情,我有兴趣了解他们的经历,哪条路线最好,1个大的int,或4个小的IP地址。

编辑 - 我们关注的一个问题是空间,这个数据库将变得非常庞大,就像每天500,000,000条记录一样。所以我们试图权衡空间问题和性能问题。

编辑2 有些对话已经转移到我们要存储的数据量......这不是我的问题。问题是哪个是存储IP地址的最佳方式以及原因。就像我在评论中所说的那样,我们为一家大型财富50强公司工作。我们的日志文件包含来自用户的使用数据。反过来,这些数据将用于安全上下文中,以驱动一些指标并驱动多个安全工具。

7 个答案:

答案 0 :(得分:24)

我建议您查看将要运行的查询类型,以决定采用哪种格式。

只有当你需要拔出或比较单个八位字节时,你才需要考虑将它们分成不同的字段。

否则,将其存储为4字节整数。这也有允许您使用MySQL内置INET_ATON()INET_NTOA()函数的好处。

性能与空间

<强>存储

如果您只支持IPv4地址,那么MySQL中的数据类型可以是UNSIGNED INT,只使用4个字节的存储空间。

要存储单个八位字节,您只需要使用UNSIGNED TINYINT数据类型,而不是SMALLINTS,每个存储将占用1个字节。

对于某些开销,两种方法都会使用类似的存储,对于单独的字段可能稍微多一点。

更多信息:

<强>性能:

使用单个字段可以产生更好的性能,它是单个比较而不是4.您提到您只对整个IP地址运行查询,因此不需要将八位字节分开。使用MySQL的INET_*函数将在文本和整数表示之间进行一次转换以进行比较。

答案 1 :(得分:13)

BIGINT8MySQL个字节。

要存储IPv4地址,UNSINGED INT就足够了,我认为这就是你应该使用的地址。

我无法想象4八位字节比单INT获得更多性能的情况,后者更方便。

另请注意,如果您要发出如下问题:

SELECT  *
FROM    ips
WHERE   ? BETWEEN start_ip AND end_ip

,其中start_ipend_ip是表格中的列,效果不佳。

这些查询用于查明给定的IP是否在子网范围内(通常是禁止它)。

为了使这些查询更有效,您应该将整个范围存储为LineString对象,并在其上添加SPATIAL索引,并查询如下:

SELECT  *
FROM    ips
WHERE   MBRContains(?, ip_range)

有关如何操作的更多详细信息,请参阅我的博客中的此条目:

答案 2 :(得分:3)

使用PostgreSQL,有一个native data type

更严重的是,我会陷入“一个32位整数”阵营。只有当所有四个八位字节被一起考虑时,IP地址才有意义,因此没有理由将八位字节存储在数据库的单独列中。您会使用三个(或更多)不同的字段存储电话号码吗?

答案 3 :(得分:1)

拥有单独的字段对我来说听起来并不是特别明智 - 就像将邮政编码拆分成部分或电话号码一样。

如果您想要关于这些部分的具体信息,可能会有用,但我认为没有理由不使用32位int。

答案 4 :(得分:0)

旧线程,但是为了读者的利益,请考虑使用ip2long。它将ip转换为整数。

基本上,存储到数据库时将使用ip2long进行转换,而从数据库中检索时将使用long2ip进行转换。 DB中的字段类型将为INT,因此与将ip作为字符串存储相比,您将节省空间并获得更好的性能。

答案 5 :(得分:0)

为了同时兼容ipv4和ipv6,请使用VARBINARY(16),ipv4始终为BINARY(4),ipv6始终为BINARY(16),因此VARBINARY(16)似乎是同时支持这两种方式的最有效方法。并将其从普通可读格式转换为二进制格式,请使用INET6_ATON('127.0.0.1'),然后将其反转,请使用INET6_NTOA(binary)

答案 6 :(得分:-1)

有效地将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";
}