Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL IP地址在数据库里存储

一文详解MySQL的IP地址如何在数据库里存储

作者:Sprintz4r

存储 IP 地址是系统开发中的常见需求,主要用途包括:安全审计与防护,用户分析与画像,网络与设备管理,日志分析与追踪,本文通过代码示例给大家介绍了MySQL的IP地址如何在数据库里存储,需要的朋友可以参考下

一、为什么要存 IP 地址?

存储 IP 地址是系统开发中的常见需求,主要用途包括:

二、两种存储方式对比

IPv4 地址本质是一个 32 位二进制数,通常以点分十进制呈现,如 192.168.1.1

在数据库中存储 IP 地址,主要有两种方式:

2.1 字符串存储(VARCHAR)

直接将 IP 地址作为字符串存储,IPv4 常用 VARCHAR(15)

CREATE TABLE ip_records (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_address VARCHAR(15)
);

INSERT INTO ip_records (ip_address) VALUES ('192.168.1.1');
维度说明
✅ 优点直观易懂,直接插入、查询和显示,无需额外转换
❌ 缺点占用存储空间较大;字符串比较性能较低;不利于范围查询

2.2 整数存储(INT UNSIGNED)

将 IPv4 地址转换为 32 位无符号整数,使用 INT UNSIGNED 存储。

CREATE TABLE ip_records (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_address INT UNSIGNED
);

-- 插入时转换
INSERT INTO ip_records (ip_address) VALUES (INET_ATON('192.168.1.1'));

-- 查询时还原
SELECT INET_NTOA(ip_address) AS ip FROM ip_records;
维度说明
✅ 优点仅占 4 字节,空间小;整数比较性能高;天然支持范围查询BETWEEN
❌ 缺点需要额外转换,不够直观,增加开发复杂度

2.3 综合对比

对比维度VARCHAR(15)INT UNSIGNED
存储空间~15 字节4 字节
索引效率较低较高
范围查询不友好天然支持 BETWEEN
可读性直接可读INET_NTOA() 转换
开发复杂度

推荐:对性能有要求、需要范围查询(如 IP 段匹配)的场景,优先使用整数存储。

三、MySQL 内置函数

3.1 IPv4

函数方向示例
INET_ATON()字符串 → 整数INET_ATON('192.168.1.1')3232235777
INET_NTOA()整数 → 字符串INET_NTOA(3232235777)'192.168.1.1'

3.2 IPv6

IPv6 地址为 128 位,无法用 INT UNSIGNED 存储,需使用 VARBINARY(16)

函数方向示例
INET6_ATON()字符串 → 二进制INET6_ATON('2001:db8::1')VARBINARY(16)
INET6_NTOA()二进制 → 字符串INET6_NTOA(...)'2001:db8::1'
-- IPv6 存储示例
CREATE TABLE ip_records_v6 (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_address VARBINARY(16)
);

INSERT INTO ip_records_v6 (ip_address) VALUES (INET6_ATON('2001:db8::1'));

SELECT INET6_NTOA(ip_address) AS ip FROM ip_records_v6;

3.3 转换原理

IPv4

IPv4 是 32 位二进制数,分为 4 个字节(Octet),每个字节对应点分十进制中的一段。

计算方式:每段 × 256 的幂次,然后求和(等价于将 4 个字节拼成一个 32 位无符号整数)。

192.168.1.1

192 × 256³ = 192 × 16,777,216 = 3,221,225,472
168 × 256² = 168 ×     65,536 =    11,010,048
  1 × 256¹ =   1 ×        256 =           256
  1 × 256⁰ =   1 ×          1 =             1
───────────────────────────────────────────────
           总和 = 3,232,235,777

从二进制视角看更直观:

192      → 11000000
168      → 10101000
  1      → 00000001
  1      → 00000001

拼接为 32 位:11000000 10101000 00000001 00000001
转为十进制:3,232,235,777

公式INET_ATON(A.B.C.D) = A × 2²⁴ + B × 2¹⁶ + C × 2⁸ + D

反向转换 INET_NTOA() 就是将整数按每 8 位拆开,转回点分十进制。

IPv6

IPv6 是 128 位,分为 8 组,每组 16 位(2 字节),用冒号分隔的十六进制表示。

::零压缩(zero compression),表示中间全是 0。先展开:

2001:db8::1
    ↓ 展开 ::
2001:0db8:0000:0000:0000:0000:0000:0001

每组是 16 位(2 字节),8 组 × 2 字节 = 16 字节,所以用 VARBINARY(16) 存储:

组1: 2001 → 0x20 0x01
组2: 0db8 → 0x0d 0xb8
组3: 0000 → 0x00 0x00
组4: 0000 → 0x00 0x00
组5: 0000 → 0x00 0x00
组6: 0000 → 0x00 0x00
组7: 0000 → 0x00 0x00
组8: 0001 → 0x00 0x01
───────────────────────
最终 16 字节(十六进制):
0x20 0x01 0x0D 0xB8 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01

要点:IPv6 没有"转成一个巨大整数"的做法,因为 128 位超出了 MySQL 整型的最大范围(BIGINT UNSIGNED 也只有 64 位)。所以直接用原始二进制 VARBINARY(16) 存储,不做数值运算,只做字节序列比较

四、实战:IP 范围查询

整数存储的一大优势是范围查询非常高效:

-- 查询 192.168.1.0 ~ 192.168.1.255 网段内的所有 IP
SELECT INET_NTOA(ip_address) AS ip
FROM ip_records
WHERE ip_address BETWEEN INET_ATON('192.168.1.0') 
                     AND INET_ATON('192.168.1.255');

如果使用 VARCHAR 存储,这种范围查询几乎无法高效实现。

五、小结

  1. 能存整数就别存字符串INT UNSIGNED(4 字节)远优于 VARCHAR(15)(15 字节),且查询性能更好。
  2. IPv4 用 INET_ATON / INET_NTOA 做转换,简单可靠。
  3. IPv6 用 VARBINARY(16) + INET6_ATON / INET6_NTOA,注意 IPv6 是 128 位,不能用整数类型。
  4. 范围查询场景(IP 段匹配、IP 库查询等)务必使用整数/二进制存储。

到此这篇关于一文详解MySQL的IP地址如何在数据库里存储的文章就介绍到这了,更多相关MySQL IP地址在数据库里存储内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文