为何数据库推荐将IPv4地址存储为32位整数而非字符串?

目录

一、IPv4地址在数据库中的存储方式?

二、IPv4地址的存储方式比较

(一)字符串存储 vs 整数存储

(二)IPv4地址"192.168.1.8"说明

三、数据库推荐32位整数存储方式原理

四、存储方式对系统性能的影响

(一)数据准备

(二)查询效率比较

(三)索引性能比较

五、应用层IP转换操作

六、总结


干货分享,感谢您的阅读!

在这个互联网高速发展的时代,IP地址就像每一个网站的身份证,帮助我们在浩瀚的网络海洋中找到方向。但你是否想过,这些数字串究竟是如何被存储的?想象一下,如果把你的家地址写成一串长长的数字,或者把它变成一个32位的整数,这听起来像是科学家在做数学实验,但其实,这却是程序员们为提升数据库性能而进行的“魔法”。

就像在一家餐馆点菜,你可以选择一份诱人的意面(字符串存储),看起来色香味俱全,但吃完后发现胃部撑得慌;或者选择一份精简的沙拉(整数存储),虽然简单但却让你轻松自在,身心舒畅。那么,究竟哪个选择更胜一筹呢?在接下来的内容中,我们将一探究竟,揭秘IP地址存储的“幕后故事”,让你不再是一个无知的网络游民,而是一位懂得选择的智者!准备好了吗?让我们一起踏上这段探索之旅吧!

一、IPv4地址在数据库中的存储方式?

在Java开发过程中,我们通常会使用数据库来存储各种类型的数据,包括IPv4地址。但是,我们应该如何存储这些IP地址才能最大程度地提高系统的性能呢?使用字符串存储IPv4地址可能会更直观,但是否是最佳选择呢?

究竟应该如何存储IPv4地址才能最大程度地提高数据库的性能和系统的效率呢?我们进行探讨下为何数据库推荐将IPv4地址存储为32位整数而非字符串,并从Java开发者的角度分析这种存储方式对系统性能和开发流程的影响。

二、IPv4地址的存储方式比较

(一)字符串存储 vs 整数存储

存储方式优点缺点
字符串存储

直观性:更易于人类理解和查看

灵活性:可以存储不同格式的IPv4地址

存储空间消耗大:每个IPv4地址需要较大的存储空间

效率低下:字符串比较通常耗时较长

难以进行数学运算和比较:需要额外的格式转换和解析

整数存储

存储空间效率高:只需较小存储空间

查询效率高:整数比较速度更快,索引和查询效率更高

数学运算方便:可以直接进行数学运算和比较

可能丢失部分信息:无法存储IPv6地址等其他地址格式

不直观:整数表示的IPv4地址不易于人类理解和查看

(二)IPv4地址"192.168.1.8"说明

当我们将IPv4地址"192.168.1.8"存储为字符串时,以十进制格式显示,类似于我们平时在浏览器中看到的网址,这种表示方法直观而易读。但一般每个IPv4地址都需要15个字符的存储空间(包括3个"."分隔符和4个三位数的表示),当数据量大的时候可能会导致:存储空间的浪费+查询和索引时效率降低。因为数据库系统在处理字符串比较时,需要逐字符比较,这可能会增加查询时间。

当我们将IPv4地址存储为32位整数时,它们会以二进制格式表示,例如:3232235776。这种表示方法可能不太直观,但整数只需要4字节的存储空间,远远小于使用字符串存储所需的空间。这意味着在存储大量IPv4地址时,整数存储方式可以显著节省存储空间,还可以提高数据库查询和索引的效率。因为整数比较速度更快,数据库可以更快地执行查询操作,并且可以更有效地利用索引。

因此,虽然字符串存储方式可能更直观和易读,但整数存储方式在存储空间效率和查询效率方面更具优势,这就是为什么数据库通常推荐将IPv4地址存储为32位整数而不是字符串的原因。

三、数据库推荐32位整数存储方式原理

整数存储IPv4地址的原理非常简单,它是基于IPv4地址的32位二进制表示的。IPv4地址由四个8位组成,每个组都可以表示为一个0到255的十进制数,或者一个0x00到0xFF的十六进制数。因此,将IPv4地址存储为32位整数实际上是将这四个8位的组合表示为一个32位的二进制数。

具体来说,如果将IPv4地址 "192.168.1.8" 转换为32位整数的表示,可以将每个IPv4地址的部分转换为二进制形式。

对于 "192.168.1.8",分别转换为二进制:

  • 192 -> 11000000
  • 168 -> 10101000
  • 1 -> 00000001
  • 8 -> 00001000

将这四个二进制数按顺序连接起来(11000000101010000000000100001000),形成一个32位的二进制数。最后,将这个32位的二进制数转换为整数,即为 IPv4 地址 "192.168.1.8" 对应的32位整数。转换后的整数值是:3232235776(以十进制表示)。

四、存储方式对系统性能的影响

(一)数据准备

使用数据库管理工具(如MySQL Workbench、phpMyAdmin等)或者命令行工具(如MySQL的命令行客户端)连接到数据库服务器。

在数据库zyf中创建新表,用于存储IPv4地址,选择将IPv4地址存储为字符串类型或整数类型:

  • 如果选择字符串类型,可以使用VARCHAR
  • 如果选择整数类型,可以使用INT

具体如下:

-- 创建表,将IPv4地址存储为字符串
CREATE TABLE ip_addresses_string (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_address VARCHAR(15)
);

-- 创建表,将IPv4地址存储为整数
CREATE TABLE ip_addresses_integer (
    id INT AUTO_INCREMENT PRIMARY KEY,
    ip_address INT UNSIGNED
);

接着我们生成大量的IPv4地址数据。可以考虑使用随机生成器来生成一系列随机的IPv4地址,以模拟真实环境中的数据。分别向 ip_addresses_stringip_addresses_integer 表中插入生成的IPv4地址数据。具体代码如下:

package org.zyf.javabasic.ipaddresses;

import java.util.Random;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;


/**
 * @program: zyfboot-javabasic
 * @description: 简单的Java程序示例,用于生成大量IPv4地址数据并插入到数据库表中
 * @author: zhangyanfeng
 * @create: 2024-05-02 23:29
 **/
public class IPAddressDataGenerator {
    public static void main(String[] args) {
        // 数据库连接信息
        String url = "jdbc:mysql://localhost:3306/zyf";
        String username = "root";
        String password = "Zyf2014";

        // 生成大量IPv4地址数据
        int numAddresses = 10000; // 要生成的IPv4地址数量
        String[] ipAddresses = generateIPv4Addresses(numAddresses);

        // 将数据插入到数据库表中
        insertData(url, username, password, ipAddresses);
    }

    // 生成大量IPv4地址数据
    private static String[] generateIPv4Addresses(int numAddresses) {
        String[] ipAddresses = new String[numAddresses];
        Random rand = new Random();

        for (int i = 0; i < numAddresses; i++) {
            // 生成随机的IPv4地址
            String ipAddress = rand.nextInt(256) + "." + rand.nextInt(256) + "." + rand.nextInt(256) + "." + rand.nextInt(256);
            ipAddresses[i] = ipAddress;
        }

        return ipAddresses;
    }

    // 将数据插入到数据库表中
    private static void insertData(String url, String username, String password, String[] ipAddresses) {
        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            // 插入字符串存储的IPv4地址数据
            insertIPv4Addresses(connection, "ip_addresses_string", ipAddresses);

            // 将IPv4地址转换为整数存储并插入数据
            long[] integerAddresses = convertToInteger(ipAddresses);
            insertIntegerAddresses(connection, "ip_addresses_integer", integerAddresses);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 插入字符串存储的IPv4地址数据
    private static void insertIPv4Addresses(Connection connection, String tableName, String[] ipAddresses) throws SQLException {
        String sql = "INSERT INTO " + tableName + " (ip_address) VALUES (?)";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            for (String ipAddress : ipAddresses) {
                statement.setString(1, ipAddress);
                statement.addBatch();
            }
            statement.executeBatch();
        }
    }

    // 将IPv4地址转换为整数存储并插入数据
    private static void insertIntegerAddresses(Connection connection, String tableName, long[] integerAddresses) throws SQLException {
        String sql = "INSERT INTO " + tableName + " (ip_address) VALUES (?)";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {
            for (long ipAddress : integerAddresses) {
                statement.setLong(1, ipAddress);
                statement.addBatch();
            }
            statement.executeBatch();
        }
    }

    // 将IPv4地址转换为整数存储
    private static long[] convertToInteger(String[] ipAddresses) {
        long[] integerAddresses = new long[ipAddresses.length];
        for (int i = 0; i < ipAddresses.length; i++) {
            String[] parts = ipAddresses[i].split("\\.");
            long ipAddress = 0;
            for (int j = 0; j < 4; j++) {
                ipAddress += Long.parseLong(parts[j]) << (24 - (8 * j));
            }
            integerAddresses[i] = ipAddress;
        }
        return integerAddresses;
    }
}

(二)查询效率比较

我们对这两种存储方式进行查询,并记录每次查询的时间。最后,我们比较两种存储方式的查询时间,以确定哪种方式的查询效率更高。代码如下:

package org.zyf.javabasic.ipaddresses;

import java.sql.*;

/**
 * @program: zyfboot-javabasic
 * @description: 比较两种存储方式的查询时间,以确定哪种方式的查询效率更高。
 * @author: zhangyanfeng
 * @create: 2024-05-02 23:44
 **/
public class IPAddressStorageComparison {
    public static void main(String[] args) {
        // Connect to the database
        Connection connection = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/zyf", "root", "Zyf2014");

            // Query IPv4 addresses stored as strings
            long startTimeString = System.currentTimeMillis();
            Statement statement = connection.createStatement();
            ResultSet resultSetString = statement.executeQuery("SELECT * FROM ip_addresses_string WHERE ip_address = '192.168.1.1'");
            long endTimeString = System.currentTimeMillis();
            long durationString = endTimeString - startTimeString;
            System.out.println("Query time for string storage: " + durationString + " milliseconds");

            // Query IPv4 addresses stored as integers
            long startTimeInteger = System.currentTimeMillis();
            ResultSet resultSetInteger = statement.executeQuery("SELECT * FROM ip_addresses_integer WHERE ip_address = 3232235777");
            long endTimeInteger = System.currentTimeMillis();
            long durationInteger = endTimeInteger - startTimeInteger;
            System.out.println("Query time for integer storage: " + durationInteger + " milliseconds");

            // Close the connection
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

具体运行如下:

根据查询时间,可以看出整数存储的查询时间明显短于字符串存储的查询时间。整数存储的查询时间为4毫秒,而字符串存储的查询时间为19毫秒。这表明在这次测试中,整数存储的查询效率要比字符串存储的查询效率高。

(三)索引性能比较

在数据库表中分别为IPv4地址字段创建索引,具体如下:

-- 为字符串存储的IPv4地址字段创建索引
CREATE INDEX idx_ip_address_string ON ip_addresses_string (ip_address);

-- 为整数存储的IPv4地址字段创建索引
CREATE INDEX idx_ip_address_integer ON ip_addresses_integer (ip_address);

这个时候在运行上面的代码,输出如下:

根据查询时间结果,可以看出整数存储的索引查询时间明显短于字符串存储的索引查询时间,整数存储的索引查询时间为1毫秒,而字符串存储的索引查询时间为10毫秒。这表明在这次测试中,整数存储的索引查询效率要比字符串存储的索引查询效率更高。

五、应用层IP转换操作

提供一个IPUtils 工具类用于IPv4地址和长整型数值之间的相互转换。通过位运算和位掩码,避免了字符串操作和对象创建,提高转换过程的执行效率:

package org.zyf.javabasic.ipaddresses;

/**
 * @program: zyfboot-javabasic
 * @description: 使用位运算和位掩码来进行IPv4地址和长整型数值的转换
 * @author: zhangyanfeng
 * @create: 2024-05-03 00:08
 **/
public class IPUtils {
    public static long ipToLong(String ip) {
        String[] parts = ip.split("\\.");
        return (Long.parseLong(parts[0]) << 24) +
                (Long.parseLong(parts[1]) << 16) +
                (Long.parseLong(parts[2]) << 8) +
                Long.parseLong(parts[3]);
    }

    public static String longToIp(long longIp) {
        StringBuilder sb = new StringBuilder();
        sb.append((longIp >>> 24) & 0xFF).append(".");
        sb.append((longIp >>> 16) & 0xFF).append(".");
        sb.append((longIp >>> 8) & 0xFF).append(".");
        sb.append(longIp & 0xFF);
        return sb.toString();
    }

    public static void main(String[] args) {
        String ip1 = "10.122.28.76";
        long ip1ToLong = ipToLong(ip1);
        System.out.println("IPv4地址 \"" + ip1 + "\" 转换为长整型数值的结果是:" + ip1ToLong);

        String ip2 = "10.168.0.45";
        long ip2ToLong = ipToLong(ip2);
        System.out.println("IPv4地址 \"" + ip2 + "\" 转换为长整型数值的结果是:" + ip2ToLong);

        long longIp = 197958752L;
        String longIpToIp = longToIp(longIp);
        System.out.println("长整型数值 \"" + longIp + "\" 转换为IPv4地址的结果是:" + longIpToIp);
    }
}

六、总结

探讨在Java开发中存储IPv4地址的最佳方式。通过对比字符串存储和整数存储两种方式的优缺点,我们发现整数存储方式在存储空间效率、查询效率和数学运算方面更具优势。虽然字符串存储方式更直观易读,但在处理大量数据时会浪费存储空间并降低查询效率。

通过具体的示例代码演示了如何生成大量的IPv4地址数据,并将其插入到数据库表中。通过查询和索引效率的比较,我们验证了整数存储方式在性能方面的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/914523.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

独家|京东上线自营秒送,拿出二十年底牌和美团竞争

京东自营秒送开启招商&#xff0c;即时零售也要全托管&#xff1f; 作者|王迟 编辑|杨舟 据「市象」独家获悉&#xff0c;京东将在近期上线自营秒送业务&#xff0c;目前已经开始邀约制招商。「市象」获得的招商资料显示&#xff0c;和5月刚升级上线的京东秒送以POP模式不同&…

观成科技:Vagent注入的内存马加密通信特征分析

概述 vagent是一个使用Java语言开发的内存马注入工具。攻击者在利用vagent注入内存马之后可以利用别的代理工具或是webshell工具连接内存马进行通信。vagent对部分工具的内存马做了一些简单的魔改以达到绕过部分检测设备的目的。 vagent注入的内存马通信特征分析 vagent工具…

新增支持Elasticsearch数据源,支持自定义在线地图风格,DataEase开源BI工具v2.10.2 LTS发布

2024年11月11日&#xff0c;人人可用的开源BI工具DataEase正式发布v2.10.2 LTS版本。 这一版本的功能变动包括&#xff1a;数据源方面&#xff0c;新增了对Elasticsearch数据源的支持&#xff1b;图表方面&#xff0c;对地图类和表格类图表进行了功能增强和优化&#xff0c;增…

Ubuntu24.04安装搜狗输入法详细教程

本章教程,介绍如何在Ubuntu24.04版本操作系统上安装搜狗输入法。 一、下载安装包 搜狗输入法linux版本下载地址:https://shurufa.sogou.com/linux 二、安装步骤 1、更新源 sudo apt update2、安装fcitx输入法框架 sudo apt install fc

vxe-table 3.10+ 进阶高级用法(一),根据业务需求自定义实现筛选功能

vxe-table 是vue中非常强大的表格的&#xff0c;公司项目中复杂的渲染都是用 vxe-table 的&#xff0c;对于用的排序。筛选之类的都能支持&#xff0c;而且也能任意扩展&#xff0c;非常强大。 默认筛选功能 筛选的普通用法就是给对应的列指定参数&#xff1a; filters&#…

一文搞懂 ARM 64 系列: PACISB

1 PAC AMR64提供了PAC(Pointer Authentication Code)机制。 所谓PAC&#xff0c;简单来说就是使用存储在芯片硬件上的「密钥」&#xff0c;一个「上下文」&#xff0c;与「指针地址」进行加密计算&#xff0c;得出一个「签名」&#xff0c;将这个「签名」写入指针的高bit上。 计…

Spark 共享变量:广播变量与累加器解析

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…

基于Matlab 火焰识别技术

课题介绍 森林承担着为人类提供氧气以及回收二氧化碳等废弃气体的作用&#xff0c;森林保护显得尤其重要。但是每年由于火灾引起的事故不计其数&#xff0c;造成重大的损失。如果有一款监测软件&#xff0c;从硬件处获得的图像中监测是否有火焰&#xff0c;从而报警&#xff0…

Group By、Having用法总结(常见踩雷点总结—SQL)

Group By、Having用法总结 目录 Group By、Having用法总结一、 GROUP BY 用法二、 HAVING 用法三、 GROUP BY 和 HAVING 的常见踩雷点3.1 GROUP BY 选择的列必须出现在 SELECT 中&#xff08;&#x1f923;最重要的一点&#xff09;3.2 HAVING 与 WHERE 的区别3.3 GROUP BY 可以…

《JavaEE进阶》----20.<基于Spring图书管理系统①(登录+添加图书)>

PS&#xff1a;关于接口定义 接口定义&#xff0c;通常由服务器提供方来定义。 1.路径&#xff1a;自己定义 2.参数&#xff1a;根据需求考虑&#xff0c;我们这个接口功能完成需要哪些信息。 3.返回结果&#xff1a;考虑我们能为对方提供什么。站在对方角度考虑。 我们使用到的…

并发基础:(淘宝笔试题)三个线程分别打印 A,B,C,要求这三个线程一起运行,打印 n 次,输出形如“ABCABCABC....”的字符串

🚀 博主介绍:大家好,我是无休居士!一枚任职于一线Top3互联网大厂的Java开发工程师! 🚀 🌟 在这里,你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人,我不仅热衷于探索一些框架源码和算法技巧奥秘,还乐于分享这些宝贵的知识和经验。 💡 无论你是刚刚踏…

华为ensp实验二--mux vlan的应用

一、实验内容 1.实验要求&#xff1a; 在交换机上创建三个vlan&#xff0c;vlan10、vlan20、vlan100&#xff0c;将vlan100设置为mux-vlan&#xff0c;将vlan10设置为group vlan&#xff0c;将vlan20设置为separate vlan&#xff1b;实现vlan10的设备在局域网内可以进行互通&…

Hadoop + Hive + Apache Ranger 源码编译记录

背景介绍 由于 CDH&#xff08;Clouderas Distribution Hadoop &#xff09;近几年已经开始收费并限制节点数量和版本升级&#xff0c;最近使用开源的 hadoop 搭了一套测试集群&#xff0c;其中的权限管理组件用到了Apache Ranger&#xff0c;所以记录一下编译打包过程。 组件…

物联网对商业领域的影响

互联网彻底改变了通信方式&#xff0c;并跨越了因地理障碍造成的人与人之间的鸿沟。然而&#xff0c;物联网&#xff08;IoT&#xff09;的引入通过使设备能够连接到互联网&#xff0c;改变了设备的功能。想象一下&#xff0c;你的闹钟连接到互联网&#xff0c;并且能够用你的声…

PYNQ 框架 - 中断(INTR)驱动

目录 1. 简介 2. 分析 2.1 Block Design 2.2 AXI Timer 2.2.1 IP 基本信息 2.2.2 IP 地址空间 2.2.3 级联模式 2.2.4 生成/捕获模式 2.3 AXI Interrupt 2.3.1 IP 基本信息 2.3.2 IP 地址空间 2.3.3 相关概念 2.3.4 参数配置 2.3.5 中断确认寄存器 3. PYNQ 代码 …

HTB:Photobomb[WriteUP]

目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行端口开放扫描 再次使用nmap对靶机开放端口进行脚本、服务扫描 使用ffuf进行简单的子域名扫描 使用浏览器直接访问该域名 选取一个照片进行下载&#xff0c;使用Yakit进行抓包 USER_FLAG&#xff1a;a9afd9220ae2b5731…

ts枚举 enum

枚举&#xff08; enum &#xff09;可以定义⼀组命名常量&#xff0c;它能增强代码的可读性&#xff0c;也让代码更好维护。调用函数时传参时没有任何提示&#xff0c;编码者很容易写错字符串内容。并且⽤于判断逻辑的是连续且相关的⼀组值&#xff0c;那此时就特别适合使用枚…

Android Studio | 修改镜像地址为阿里云镜像地址,启动App

在项目文件的目录下的 settings.gradle.kts 中修改配置&#xff0c;配置中包含插件和依赖项 pluginManagement {repositories {maven { urluri ("https://www.jitpack.io")}maven { urluri ("https://maven.aliyun.com/repository/releases")}maven { urlu…

场景解决之mybatis当中resultType= map时,因某个字段为null导致返回的map的key不存在怎么处理

1、场景:通过查询数据表将返回结果封装到map当中返回,因某个字段为null,导致map当中key丢失 <select id"queryMyBonus" parameterType"com.cn.entity.student" resultType "map">SELECTb.projectName as "projectName",b.money…

初识算法 · 位运算常见总结(1)

目录 前言&#xff1a; 位运算基本总结 部分题目代码 前言&#xff1a; ​本文的主题是位运算&#xff0c;通过常见的知识点讲解&#xff0c;并且会附上5道简单的题目&#xff0c;5道题目的链接分别为&#xff1a;191. 位1的个数 - 力扣&#xff08;LeetCode&#xff09; 1…