本周我们在办公室里进行了一场健康的辩论。我们正在创建一个Db来存储代理信息,因为除了我们应该如何存储IP之外,我们大部分都已经制定了模式。一个阵营想要使用4个小点,一个用于每个八位位组,另一个想要使用一个大的int,INET_ATON。
这些表格将是巨大的,因此性能是关键。我在这里中间,因为我通常在我的世界中使用MS SQL和4个小的int。我对这种类型的卷存储IP没有足够的经验。
我们将使用perl和python脚本来访问数据库,以进一步将数据标准化为其他几个表格,用于高级谈话者,有趣的流量等。
我确信社区中有一些人已经做了与我们正在做的事情类似的事情,我有兴趣了解他们的经历,哪条路线最好,1个大的int,或4个小的IP地址。
编辑 - 我们关注的一个问题是空间,这个数据库将变得非常庞大,就像每天500,000,000条记录一样。所以我们试图权衡空间问题和性能问题。
编辑2 有些对话已经转移到我们要存储的数据量......这不是我的问题。问题是哪个是存储IP地址的最佳方式以及原因。就像我在评论中所说的那样,我们为一家大型财富50强公司工作。我们的日志文件包含来自用户的使用数据。反过来,这些数据将用于安全上下文中,以驱动一些指标并驱动多个安全工具。
答案 0 :(得分:24)
我建议您查看将要运行的查询类型,以决定采用哪种格式。
只有当你需要拔出或比较单个八位字节时,你才需要考虑将它们分成不同的字段。
否则,将其存储为4字节整数。这也有允许您使用MySQL内置INET_ATON()
和INET_NTOA()
函数的好处。
<强>存储强>
如果您只支持IPv4地址,那么MySQL中的数据类型可以是UNSIGNED INT
,只使用4个字节的存储空间。
要存储单个八位字节,您只需要使用UNSIGNED TINYINT
数据类型,而不是SMALLINTS
,每个存储将占用1个字节。
对于某些开销,两种方法都会使用类似的存储,对于单独的字段可能稍微多一点。
更多信息:
<强>性能:强>
使用单个字段可以产生更好的性能,它是单个比较而不是4.您提到您只对整个IP地址运行查询,因此不需要将八位字节分开。使用MySQL的INET_*
函数将在文本和整数表示之间进行一次转换以进行比较。
答案 1 :(得分:13)
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)
有关如何操作的更多详细信息,请参阅我的博客中的此条目:
答案 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";
}