在数据库中存储IP的最佳方法是什么?

56

在MySQL数据库中,存储IP地址的最佳字段类型和长度是什么?

IPv6呢?


请查看此处的讨论:https://dev59.com/_HRB5IYBdhLWcg3w-8Ho - Elbert Alias
6个回答

61

将IP地址存储为INT(11) UNSIGNED,然后使用INET_ATONINET_NTOA函数来存储/检索IP地址。

示例代码:

INSERT table(ip) VALUES (INET_ATON('192.168.0.1')); /*ip = 3232235521*/
SELECT INET_NTOA(ip) As IPAddress FROM table; /*IPAddress = 192.168.0.1*/

6
在PHP端,您可以尝试使用ip2longlong2ip函数。 - Thai
19
我认为这不会支持IPv6。 - Michael Aaron Safyan
4
是的,这位发帖者显然没有考虑IPv6,但他应该考虑。 - Michael Aaron Safyan
3
为什么你应该处理INET函数。基本上,你正在记录从网络堆栈传递给你的IP地址。只需将其存储为提供给你的形式(希望是作为字符串)。这样,当IPv8到来时,你就不必更改数据库模式。 - Richard Schneider
6
“(11)”不是必需的,它只是给mysql一个提示,告诉它你想显示多少位数字。在内部,它始终是一个完整的32位整数。 - Marc B
显示剩余13条评论

18

这取决于你想用它来做什么,但最简单的方法可能是将其表示为一个字符串。而这个问题涵盖了处理它所需的字符数(它是45)。


1
没错,对的。目前我们有两种形式的IP地址(IPv4和IPv6)。谁知道未来20年会出现什么新形式。我们只需将其存储为vchar,不必担心。 - Richard Schneider
1
感谢您的支持,Richard。我认为我们不需要担心IPv6以外的问题,但是除了IPv4之外,对IPv6的支持是必须的。 - Michael Aaron Safyan
1
@RichardSchneider,IPv6旨在超越200年的设计寿命。 - Pacerier
1
尽管务实,但应该规范用于存储地址的格式。在IPv6的情况下,人们应该采用一种定义良好的方式来(不)缩短地址,跳过所有零组并缩写“::”。否则,很难轻松地查询相同但呈现不同的地址。 - ojdo

12
如果您想支持IPv6和IPv4,请将其存储为BINARY(16)并在插入到数据库之前转换IP地址。例如,在PHP中(与MySQL通常一起使用的语言),您可以使用inet_pton()函数来完成此操作。

6
IPv6地址是128位(16字节),因此需要足够大的字段来存储它。此外,您可能需要一个字段来指示IP是IPv4还是IPv6(在IPv6中,::192.168.4.10在数字上与IPv4中的192.168.4.10相同,但根据您的应用程序,您可能需要区分这两者)。
如果您需要存储子网,则可能希望存储子网的第一个地址、CIDR掩码和计算出的上限地址(广播地址)。这将有助于搜索,以便您可以执行像这样的查询。
SELECT * FROM networks WHERE lowerBound<=MYIP AND upperBound>=MYIP

如果您正在使用子网,您也应该自己计算下限,并不仅仅依赖于用户正确地执行此操作(伪代码):
lowerBound = AND(networkAddress, subnetMask)
upperBound = OR(lowerBound, complement(subnetMask))

这适用于IPv4和IPv6。

4
如果您计划通过IP地址搜索数据库,则INT查询速度更快。如果仅用于显示(例如在日志输出中),则字符串更好,因为您不需要来回转换。

0
我完全同意Scrum Meister的观点,使用INT(11) UNSIGNED并在INET函数中进行存储/检索是最好的方式,但有时如果你不打算按子网进行查询,可以选择使用VARCHAR(45)

为什么你需要处理INET函数呢?基本上,你正在记录从网络堆栈传递给你的IP地址。只需将其存储为所给出的形式(希望是字符串)。这样,当IPv8到来时,你就不必更改数据库模式。 - Richard Schneider
我同意 - 在网络实践中,“最佳”方法是使用INET函数,这样您就可以按子网查询...如果您不需要此类功能,则最好将其存储为足够大以容纳IPv6的字符串。 - philwinkle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接