Yihui’s Blog

数据库应该用什么类型存储 IP 地址?

日期:2026-07-11
标签:#面试 #八股 #后端 #数据库 #场景题

一句话答案

若只支持 IPv4 可存无符号 32 位整数;兼容 IPv4 和 IPv6 时优先存 16 字节二进制,并在应用边界使用标准转换函数。

面试口语版

不建议默认用可变字符串直接存 IP。IPv4 本质是 32 位,可使用 MySQL INT UNSIGNED;如果系统需要兼容 IPv6,统一使用 VARBINARY(16) 或 BINARY(16) 更节省空间,也更适合索引和范围查询。MySQL 可用 INET6_ATON 把文本转二进制,用 INET6_NTOA 转回展示。选择定长还是变长取决于是否统一保存为 16 字节表示以及数据库约定。

方案对比

类型空间IPv6查询与索引
VARCHAR(39)较大支持文本格式不统一,范围查询不便
INT UNSIGNED4 字节不支持IPv4 高效
VARBINARY(16)4/16 字节支持紧凑,适合索引与网段判断

关键细节

  • IPv6 文本存在压缩和大小写等多种等价形式,直接按字符串比较不可靠。
  • Java 中不要用有符号 int 的正负语义表示 IPv4 数值,可使用 long 或字节数组。
  • 如果需要 CIDR 网段检索,应保存二进制地址、前缀长度或额外维护范围起止值。
  • 日志展示和数据库存储可以采用不同格式。

面试官追问

  1. IPv4 如何转换成 32 位整数?
  2. 如何判断一个 IP 是否属于某个 CIDR?
  3. IPv4-mapped IPv6 地址如何处理?

面试官追问参考答案

1. IPv4 如何转换成 32 位整数?

将四段 a.b.c.d 转为 (a<<24)|(b<<16)|(c<<8)|d。Java 应用 long 承载无符号结果并对每段校验 0–255;反向则依次无符号右移并与 0xff。

2. 如何判断一个 IP 是否属于某个 CIDR?

把 IP 和网段地址转二进制,根据前缀长度生成掩码,判断 (ip & mask) == (network & mask)。IPv6 同理使用 128 位字节数组;数据库查询可保存范围起止值,或使用数据库原生网络类型与运算符。

3. IPv4-mapped IPv6 地址如何处理?

它通常形如 ::ffff:a.b.c.d。系统应在入口规定统一规范:要么保留 16 字节映射形式,要么识别后规范为 4 字节 IPv4;比较、唯一约束和网段规则必须使用同一种表示,避免同一地址存两份。

学习清单

  • 掌握 IPv4 的 32 位表示和 IPv6 的 128 位表示。
  • 了解 MySQL INET6_ATON/INET6_NTOA。
Maintained by · YihuiEdit on GitHub

Keep reading

View all posts