查找在MySQL中存储IP以获得更好性能的方法

x8diyxa7  于 2023-01-20  发布在  Mysql
关注(0)|答案(7)|浏览(128)

本周我们在办公室里进行了一场健康的辩论。我们正在创建一个DB来存储代理信息,除了如何存储IP之外,我们已经制定了大部分的模式。一个阵营希望使用4个smallint,每个octet一个,另一个阵营希望使用1个大int,INET_ATON。
这些表将是巨大的,所以性能是关键。我在这里的中间,因为我通常使用MS SQL和4个小int在我的世界。我没有足够的经验与这种类型的卷存储IP。
我们将使用perl和python脚本来访问数据库,以进一步将数据规范化到其他几个表中,用于最大流量者、感兴趣的流量等。
我敢肯定,在社区中有一些人已经做了一些类似于我们正在做的事情,我有兴趣听到他们的经验,以及哪条路由是最好的,1个大整数,或4个小整数的IP地址。

EDIT-空间是我们关注的问题之一,该数据库将非常庞大,每天可容纳5亿条记录。因此,我们正在尝试权衡空间问题沿着性能问题。
EDIT 2有些主题已经转到我们要存储的数据量上......这不是我的问题。问题是哪种存储IP地址的方式更好,为什么。就像我在评论中说的,我们为一家财富50强的大公司工作。2我们的日志文件包含用户的使用数据。这些数据又将在安全上下文中用于驱动一些指标和驱动几个安全工具。

4si2a6ki

4si2a6ki1#

我建议看看您将运行什么类型的查询来决定采用哪种格式。
只有当您需要取出或比较单个八位字节时,才必须考虑将它们拆分为单独的字段。
否则,将其存储为4字节整数,这样还可以使用MySQL内置的INET_ATON()INET_NTOA()函数。

性能与空间

    • 储存:**

如果您只打算支持IPv4地址,那么MySQL中的数据类型可以是UNSIGNED INT,它只使用4字节的存储空间。
要存储单个八位字节,您只需要使用UNSIGNED TINYINT数据类型,而不是SMALLINTSSMALLINTS将占用每个八位字节的存储空间。
这两种方法都使用类似的存储空间,对于单独的字段可能会稍微多一些,以增加一些开销。
更多信息:

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

cwxwcias

cwxwcias2#

一个BIGINTMySQL中的8个字节。
要存储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)

请看我博客中的这篇文章,了解如何做到这一点的更多细节:

2eafrhcq

2eafrhcq3#

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

pgx2nnw8

pgx2nnw84#

有单独的字段对我来说听起来并不特别明智--就像把一个邮政编码分成几个部分或一个电话号码一样。
如果你想知道关于这些部分的具体信息,这可能会很有用,但是我看不出有什么真实的的理由不使用32位int。

ccrfmcuu

ccrfmcuu5#

要同时兼容ipv4和ipv6,请使用VARBINARY(16),ipv4的将始终为BINARY(4),ipv6的将始终为BINARY(16),因此VARBINARY(16)似乎是同时支持这两种格式的最有效方法。要将它们从正常可读格式转换为二进制格式,请使用INET6_ATON('127.0.0.1'),要反转此操作,请使用INET6_NTOA(binary)

r6hnlfcb

r6hnlfcb6#

IP到int和int到IP的高效转换(可能对您有用):(波兰语)

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";
}
qf9go6mv

qf9go6mv7#

旧线程,但为了读者的利益,考虑使用ip2long。它将ip转换为整数。
基本上,当存储到DB中时,您将使用ip2long进行转换,然后当从DB中检索时,使用long2ip进行转换。DB中的字段类型将为INT,因此与将ip存储为字符串相比,您将保存空间并获得更好的性能。

相关问题