Mysql 如何在关系数据库中存储与IPv6兼容的地址

Mysql 如何在关系数据库中存储与IPv6兼容的地址,mysql,ipv6,Mysql,Ipv6,我该怎么做 现在,将不使用IPv6,但我需要设计应用程序,使其为IPv6做好准备。有必要在MySQL数据库中存储IP地址和CIDR块(也是BGP NLRI,但这是另一种情况)。我总是用INT表示IPv4,用TINYINT表示masklen,但IPv6是128位的 哪种方法最适合这样做2xBIGINT字符(16)用于二进制存储字符(39)用于文本存储8xSMALLINT 您会推荐什么?我不确定MySQL的正确答案是什么,因为它还不支持IPv6地址格式(虽然“”表示它将采用MySQL v6.0,但当

我该怎么做

现在,将不使用IPv6,但我需要设计应用程序,使其为IPv6做好准备。有必要在MySQL数据库中存储IP地址和CIDR块(也是BGP NLRI,但这是另一种情况)。我总是用INT表示IPv4,用TINYINT表示masklen,但IPv6是128位的

哪种方法最适合这样做<代码>2xBIGINT<代码>字符(16)用于二进制存储<代码>字符(39)用于文本存储<是否在专用表格中编码>8xSMALLINT

您会推荐什么?

我不确定MySQL的正确答案是什么,因为它还不支持IPv6地址格式(虽然“”表示它将采用MySQL v6.0,但当前文档没有对此进行备份)


然而,对于你建议的那些,我建议使用2*BIGINT,但要确保它们是未签名的。在IPv6中,在/64地址边界处有一种自然的分割(因为a/64是最小的netblock大小),这将很好地符合这一点。

对于二进制有意义的程序,IP地址将被使用吗?还是最好存储一个文本表示?另外,在IPv6中,您通常不太可能使用地址,而更可能使用主机名。这是否相关部分取决于应用程序。CHAR(16)将是一个糟糕的选择;char用于字符数据,不喜欢IPv6地址中普遍存在的零字节大数据流。2 x BIGINT会让人不舒服-两个字段实际上是一个字段(加上存储的值是big-endian还是little-endian?)。我使用了固定大小的二进制类型,如果没有,则使用blob类型。

如果您倾向于使用char(16),则一定要使用BINARY(16)。二进制(n)没有排序规则或字符集的概念(或者更确切地说,它是一个字符集/排序规则为“二进制”的字符(n))。mysql中char的默认值为latin1_swedish_ci,这意味着它将尝试对latin1中有效代码点的字节值进行不区分大小写的排序和比较,这将导致各种意外问题


另一种选择是使用十进制(39,0)无符号零填充,效率不如两个bigint(在当前版本的mysql中,十进制将使用每九位4字节),但允许您将所有内容保存在一列中并很好地打印出来。

我选择完整的39字符“标准”打印格式:--

“2001:0db8:85a3:0000:0000:8a2e:0370:7334” 40和空终止符


这是*nix命令行工具所使用的格式,也是通常报告IPV6地址的格式(?)。

我正在处理一个最长前缀匹配的项目,因此我将地址分成4个整数作为IPv4地址。它工作得很好。我将其扩展到IPv6地址。

请注意,IPv6地址(包括作用域标识符)的最大长度为46字节,这是由标准C标头中的INET6_ADDRSTRLEN定义的。对于Internet使用,您应该能够忽略(%10、#eth0等),但只需注意返回的结果是否比预期的长。

如果将其存储在二进制文件中,则永远不会有机会在数据库本身中执行位运算符来查找匹配的地址(即,与特定子网匹配的所有地址)这就是为什么我建议使用文本格式——您可以使用它进行正则表达式匹配(尽管我没有提到)。将其存储为任何二进制格式都会很棘手,除非您将其升级为完整的用户定义类型(MySQL支持吗?),并提供适当的运算符。我不会。IPv6地址通常以缩写格式显示,在表中搜索特定子网中的任何地址也会非常低效,特别是当子网跨越Nyble边界时。@James Anderson:更糟糕的是,您无法比较给定IPv6是否位于指定范围内(地理定位,IP范围禁止).@对于IPv4虚线格式,这是真的。但是,可以使用扩展形式的IPv6打印格式(39个字符)进行比较。最终决定:2xBIGINT如果第二个bigint为NULL,则表示IPv4实际上-如果我这样做,我会将IPv4的第一个bigint保留为NULL,或者使用单独的字段。这样,IPv4部分以最不重要的字显示。如果我这样做,我会以IPv6地址的V4COMPAT格式存储IPv4地址,即::/96范围。不能只使用两个BIGINT,必须使用两个BIGINT unsigned。如果以FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF为例,将其一分为二并将每边转换为其整数表示形式,将解析为两个值18446744073709551615。这是一个无符号64位整数的最大值。@詹姆斯:现在IPv4映射地址::ffff:/96范围在我正在处理的一个项目中,我们使用十进制(39,0)方法,效果很好,很少有例外。有时,您必须强制转换值以进行比较。i、 e.其中ipv6=CAST('包含数字ipv6的字符串'为十进制(39,0))。特别是在不支持128位数字类型的语言上,mysql库的参数绑定不够聪明。 "2001:0db8:85a3:0000:0000:8a2e:0370:7334"