我正在更改一些表以将IP地址存储为数字而不是字符串。这对于IPv4来说很简单,其中32位地址可以适合整数列。但是,IPv6地址是128位。
MySQL documentation仅显示最多64位的数字类型(“bigint”)。
我应该坚持使用char / varchar进行IPv6吗? (理想情况下,我想对IPv4和IPv6使用相同的列,所以我不想这样做。)
有没有比使用两个bigint列更好的东西?每当使用地址时,我宁愿不必将值分解为上限和下限/。
我正在使用MariaDB 5.1 - 如果在更高版本的MySQL中有更好的解决方案,那么很高兴知道,虽然没有立即帮助。
[编辑] 请注意,我建议最佳方式执行此操作 - 很明显有多种方法可以做到这一点(包括现有的)字符串表示),但哪个(在性能方面)最好? (即如果有人已经完成了分析,这样可以省去我的工作,或者如果我遗漏了一些明显的东西,那么知道这一点也很棒。)
答案 0 :(得分:42)
我发现自己在问这个问题,从我读过的所有帖子中都没有找到任何性能比较。所以这是我的尝试。
我创建了以下表格,填充了来自100个随机网络的2,000,000个随机IP地址。
CREATE TABLE ipv6_address_binary (
id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
addr BINARY(16) NOT NULL UNIQUE
);
CREATE TABLE ipv6_address_twobigints (
id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
haddr BIGINT UNSIGNED NOT NULL,
laddr BIGINT UNSIGNED NOT NULL,
UNIQUE uidx (haddr, laddr)
);
CREATE TABLE ipv6_address_decimal (
id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
addr DECIMAL(39,0) NOT NULL UNIQUE
);
然后我选择每个网络的所有IP地址并记录响应时间。 twobigints表上的平均响应时间约为1秒,而二进制表上的平均响应时间约为百分之一秒。
以下是查询。
注意:
X_ [HIGH / LOW]是X
的最高/最低有效64位当NETMASK_LOW为0时,省略AND条件,因为它总是产生true。不会对性能产生太大影响。
SELECT COUNT(*) FROM ipv6_address_twobigints
WHERE haddr & NETMASK_HIGH = NETWORK_HIGH
AND laddr & NETMASK_LOW = NETWORK_LOW
SELECT COUNT(*) FROM ipv6_address_binary
WHERE addr >= NETWORK
AND addr <= BROADCAST
SELECT COUNT(*) FROM ipv6_address_decimal
WHERE addr >= NETWORK
AND addr <= BROADCAST
平均响应时间:
图表:
BINARY_InnoDB 0.0119529819489
BINARY_MyISAM 0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB 0.782350552082
BIGINT_MyISAM 1.07809265852
答案 1 :(得分:4)
我总是使用一个字符串或两个64位整数。前者是我想记录的情况,后者是我需要计算特定地址是否包含在某个网络中,或者两个网络是否重叠的情况。
将其存储为整数时,唯一的选择是将其拆分为两个64位数。由于这使得比较更加繁琐,除非您需要数值计算,否则我不会这样做,以查看IP是否属于某个网络。
我不太关心将IPv6地址存储在字符串中的性能 - 这取决于您为数据执行的查找次数。通常,很少,或者只有非常少的数据。是的,存储和查找的效率低于数字,但它并不比存储电子邮件地址,人名或用户名更痛苦。
为什么你不能在字符串字段中混合使用IPv4和IPv6?检索它们时很容易区分。它们的可能值范围不重叠。
简而言之:使用数字来检查重叠,在别处使用字符串。与易用性相比,字符串的低效率无关紧要。
答案 2 :(得分:1)
引用:“你考虑过二元(64)”