2013-03-23 71 views
9

当前为了保存IP地址,我将它转换为数字并将其存储在集合中。基本上我是这样做的日志目的。这意味着我很关心以尽可能快的速度和最小的空间存储信息。保存mongoDB中的IP地址

我很少将它用于查询。

我的想法,

  • 存储为字符串是肯定的低效。
  • 存储为4位数字会更慢,需要更多空间。

尽管如此,我认为这是一个适当的方法,但对我的目的有没有更好的方法呢?

+2

4个整数将不适用于IPv6地址。 4位数字*不会占用比字符串更多的空间。说实话,你必须决定从源字符串转换还是空间损失更重要,并基于此决定。 – Joe 2013-03-23 19:40:54

+1

你需要查询生成的结构吗?如果与其他数据库写操作竞争,MongoDB可能不是记录日志的最佳选择。尝试选项并查看它们的表现。查看该集合的“统计信息”(http://docs.mongodb.org/manual/reference/collection-statistics/),查看平均文档的大小。你可能也想在内存缓冲中做一些工作,而不是写很多小的单个文档。 – WiredPrairie 2013-03-23 21:39:22

+0

你应该转换为字符串并存储它。 – Abhishek 2013-08-17 06:58:51

回答

10

绝对IP地址保存为数字,如果你不介意的话,它需要工作的额外位,特别是如果你需要做的查询上的地址,你有大的表/集合。

这里的原因:

存储

  • IPv4地址是4个字节,如果存储为无符号整数。
  • 当以虚线形式写出字符串时,IPv4地址在10字节和18字节之间变化。 (假设平均是14个字节。)

即7-15字节字符,再加上2-3个字节,如果您使用的是可变长度的字符串类型,其变化的基础数据库,你”上重新使用。如果您有固定长度的字符串表示形式,则必须使用15个字符的固定宽度字段。

磁盘存储很便宜,所以这在大多数使用情况下都不是问题。然而,内存并不便宜,如果你有一个大的表/集合,并且你想快速查询,那么你需要一个索引。字符串编码的2-3倍存储惩罚极大地减少了您可以索引的记录数量,同时仍将索引驻留在内存中。

  • 如果存储为无符号整数,则IPv6地址为16个字节。 (可能为多个4或8字节整数,具体取决于您的平台)
  • 当以缩写的十六进制表示法编码为一个字符串时,IPv6地址范围从6字节到42字节。

在低端,环回地址(:: 1)是3个字节加上可变长度字符串开销。在高端,像2002:4559:1FE2:1FE2:4559:1FE2:4559:1FE2这样的地址使用39个字节加上可变长度的字符串开销。

与IPv4不同,假设平均IPv6字符串长度将是6和42的平均值并不安全,因为具有大量连续零的地址数量是整个IPv6地址空间的一小部分。只有一些特殊的地址,比如loopback和autoconf地址,可能以这种方式被压缩。

同样,对于字符串编码与整数编码,这是一个大于2倍的存储损失。

网络数学

你认为路由器店IP地址为字符串?当然他们不会。

如果您需要对IP地址进行网络数学计算,则字符串表示形式很麻烦。例如。如果您想编写一个查询来搜索特定子网上的所有地址(“返回IP地址为10.7.200.104/27的所有记录”,则可以通过屏蔽具有整数子网掩码的整数地址轻松完成此操作。 Mongo不支持这个特定的查询,但大多数RDBMS都这样做)。如果你将地址存储为字符串,那么你的查询将需要将每行转换为一个整数,然后对其进行掩码处理,这会降低几个数量级。对于IPv4地址,可以在几个CPU周期内使用2个寄存器完成。将字符串转换为整数需要在字符串上循环)

同样,范围查询(“返回所有记录192.168.1.50和192.168之间的所有记录.50.100“)与整数地址将能够使用索引,而字符串地址范围查询将不会。

底线

它需要更多一点的工作,但不是很多(有100万航标()和ntoa()函数在那里),但如果你正在构建什么大不了的事情做实您希望将来能够抵御未来的需求和大数据集的可能性,您应该将IP地址存储为整数,而不是字符串。

如果您正在做一些快速而肮脏的事情,并且不介意将来重塑的可能性,那么请使用字符串。

对于OP的目的,如果您针对速度和空间进行了优化,并且您不认为需要经常查询,那么为什么要使用数据库呢?只需将IP地址打印到文件。与将其存储在数据库中相比,这会更快,存储效率更高(具有相关的API和存储开销)。

0

IPv4是四个字节,因此可以将它存储到一个32位整数(BSON类型16)中。

http://docs.mongodb.org/manual/reference/bson-types

+1

我想你还没有看过我的问题。我知道我可以用这种方式储存它们,而且我已经将它写在问题中了。我正在寻找一个更详细的答案,然后只是一个单线,你可以将它们存储为一个整数。 – 2013-11-15 17:54:05

+0

我没看过。你的问题听起来像'我做到了最好的方式,但还有什么更好?'。所以基本上我的回答说'是的,我认为这是最好的方式'。而且没有必要为这样一个简单的答案写一本书。 – 2013-11-18 09:28:46

-1

IPv4最简单的方法是使用提供的有趣数学转换为int here

我使用下面的函数(JS)与DB

ipv4Number: function (ip) { 
    iparray = ip.split("."); 
    ipnumber = parseInt(iparray[3]) + 
     parseInt(iparray[2]) * 256 + 
     parseInt(iparray[1]) * Math.pow(256, 2) + 
     parseInt(iparray[0]) * Math.pow(256, 3); 
    if (parseInt(ipnumber) > 0)return ipnumber; 
    return 0; 
} 
+2

这样做绝对没有意义,因为大多数语言都有本地功能,它们的功能非常类似。此外,问题不在于如何将IP转换为整数。 – 2014-04-13 05:35:12

1

匹配的有效方式一个IP地址保存为INT之前转换。如果你想用cidr过滤器标记一个IP地址,在这里进行演示:

> db.getCollection('iptag').insert({tags: ['office'], hostmin: 2886991873, hostmax: 2887057406, cidr: '172.20.0.0/16'}) 
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173867009, hostmax: 173932542, cidr: '10.93.0.0/16'}) 
> db.getCollection('iptag').insert({tags: ['server'], hostmin: 173932545, hostmax: 173998078, cidr: '10.94.0.0/16'}) 

创建标签索引。

> db.getCollection('iptag').ensureIndex(tags: 1) 

使用cidr范围过滤ip。 ip2int('10.94.25.32') == 173938976

> db.getCollection('iptag').find({hostmin: {$lte: 173938976}, hostmax: {$gte: 173938976}})