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

news2025/1/12 23:07:21

目录

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

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

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

(二)IPv4地址"192.168.1.8"说明

三、数据库推荐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地址数据,并将其插入到数据库表中。通过查询和索引效率的比较,我们验证了整数存储方式在性能方面的优势。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

服务器IP选择

可以去https://ip.ping0.cc/查看IP的具体情况 1.IP位置--如果是国内用&#xff0c;国外服务器的话建议选择日本&#xff0c;香港这些比较好&#xff0c;因为它们离这里近&#xff0c;一般延时低&#xff08;在没有绕一圈的情况下&#xff09;。 不过GPT的话屏蔽了香港IP 2. 企…

C++ | Leetcode C++题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; class Solution { public:int minPathSum(vector<vector<int>>& grid) {if (grid.size() 0 || grid[0].size() 0) {return 0;}int rows grid.size(), columns grid[0].size();auto dp vector < vector <int>…

WebAuthn 无密码身份认证

文章目录 WebAuthn简介工作原理组成部分架构实现注册认证应用场景案例演示 WebAuthn简介 WebAuthn&#xff0c;全称 Web Authentication&#xff0c;是由 FIDO 联盟&#xff08;Fast IDentity Online Alliance&#xff09;和 W3C&#xff08;World Wide Web Consortium&#x…

【跟马少平老师学AI】-【神经网络是怎么实现的】(八)循环神经网络

一句话归纳&#xff1a; 1&#xff09;词向量与句子向量的循环神经网络&#xff1a; x(i)为词向量。h(i)为含前i个词信息的向量。h(t)为句向量。 2&#xff09;循环神经网络的局部。 每个子网络都是标准的全连接神经网络。 3&#xff09;对句向量增加全连接层和激活函数。 每个…

【Web】CTFSHOW 新手杯 题解

目录 easy_eval 剪刀石头布 baby_pickle repairman easy_eval 用script标签来绕过 剪刀石头布 需要赢100轮&#x1f914; 右键查看源码拿到提示 一眼session反序列化 打PHP_SESSION_UPLOAD_PROGRESS 脚本 import requestsp1 a|O:4:"Game":1:{s:3:"log…

如何将 redis 快速部署为 docker 容器?

部署 Redis 作为 Docker 容器是一种快速、灵活且可重复使用的方式&#xff0c;特别适合开发、测试和部署环境。本文将详细介绍如何将 Redis 部署为 Docker 容器&#xff0c;包括 Docker 安装、Redis 容器配置、数据持久化、网络设置等方面。 步骤 1&#xff1a;安装 Docker 首…

NI CRIO 9045 LABVIEW2020

1.labview工程如果要访问CRIO&#xff0c;需要设置以下&#xff0c;否则在项目中连接失败。 2.项目中如果要传文件&#xff0c;需要安装WebDEV 3.使用WebDAV将文件传输到实时(RT)目标 https://knowledge.ni.com/KnowledgeArticleDetails?idkA03q000000YGytCAG&lzh-CN

34.Docker基本操作

镜像相关的命令 镜像名称分为两部分组成&#xff1a;[repository]:[tag],tag就是镜像的版本。如果tag没有指定默认就是latest,表示最新版本的镜像。 查看docker命令的帮助信息 docker --help 具体某条命令的帮助信息 docker images --help 案例一&#xff1a;从DockerHub中…

【Vue3】openlayers加载瓦片地图并手动标记坐标点

目录 一、创建Vue3项目 二、openlayers加载瓦片地图&#xff08;引js文件版&#xff09; 2.1 将以下的文件复制到public下 2.2 index.html引入ol脚本 2.3 删除项目自带的HelloWorld.vue&#xff0c;创建Map.vue 2.4 编码Map.vue 2.5 修改App.vue 2.6 启动项目测试 三、…

数据分析--客户价值分析RFM(K-means聚类/轮廓系数)

原数据 import os import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn import metrics ### 数据抽取&#xff0c;读⼊数据 df pd.read_csv("customers1997.csv") #相对路径读取数据 print(df.info()) pr…

探索科技园区的创新应用架构

在当今科技快速发展的时代&#xff0c;科技园区已经成为了创新和技术发展的孵化器和聚集地。在这样的环境中&#xff0c;科技园区的应用架构扮演着至关重要的角色&#xff0c;它不仅需要支持各种创新型企业和科技项目的发展&#xff0c;还需要提供高效的技术基础设施和服务。下…

《架构即未来》读后感

目录 一、引言 二、《架构即未来》读后感 1、主题的简要介绍 2、我的看法和理解 3、作者的优点和传递的信息 4、思想如何适用于当今社会 三、《架构即未来》对于企业发展的影响具体体现在哪些方面&#xff1f; 一、引言 任何一个持续成长的公司最终都需要解决系统、组织…

是谁在丢盔弃甲?

原创 | 刘教链 继BTC&#xff08;比特币&#xff09;跌破关键心理位置6万刀、短促急降至56.5k之后&#xff0c;暂时技术性反弹至58.5k一线。有悲观者说&#xff0c;这是牛市的结束&#xff0c;一切都完了。说这种话的人&#xff0c;或者轻信这种话的人&#xff0c;想必都是些“…

微调Mistral 7B以实现命名实体识别 (NER)

文章来源&#xff1a;fine-tuning-mistral-7b-for-named-entity-recognition-ner 2024 年 4 月 19 日 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;命名实体识别&#xff08;NER&#xff09;被认为是一项关键任务&#xff0c;应用范围广泛&#xff0c;包括信息…

k8s部署maven项目

failed to verify certificate: x509: certificate signed by unknown authority 今天在执行kubectl get nodes的时候报的证书验证问题&#xff0c;看了一圈首次搭建k8s的都是高频出现的问题。 couldn’t get current server API group list: Get “https://kubernetes.docker…

C#描述-计算机视觉OpenCV(3):重映射

C#描述-计算机视觉OpenCV&#xff08;3&#xff09;&#xff1a;重映射 前言色彩波形图像重映射 前言 C#描述-计算机视觉OpenCV&#xff08;1&#xff09;&#xff1a;基础操作 C#描述-计算机视觉OpenCV&#xff08;2&#xff09;&#xff1a;图像处理 在前文中&#xff0c;描…

R语言学习—4—数据矩阵及R表示

1、创建向量、矩阵 在R中&#xff0c;c()函数用于创建向量或组合数据对象。它在某些情况下可能会被省略&#xff0c;因为R有一些隐式的向量创建规则。例如&#xff0c;当你使用:操作符创建一个数字序列时&#xff0c;R会自动创建一个向量&#xff0c;所以你不需要显式地调用c()…

超越数据的确定性:通过概率主成分分析拥抱不确定性

原文地址&#xff1a;beyond-determinism-in-data-embracing-uncertainty-with-probabilistic-principal-component-analysis 2024 年 4 月 24 日 主成分分析法&#xff08;Principal Component Analysis&#xff0c;PCA&#xff09;是一种统计方法&#xff0c;它可以通过正交…

蓝桥杯备战国赛1

开心的金明 火烧赤壁 南蛮图腾 #include<iostream> #include<algorithm> #include<cmath> using namespace std; int n, m; int v[30], k[30]; int arr[30010][30]; int main() {cin >> n >> m;for (int i 1;i < m;i){cin >> v[i] &g…

自定义表单元素组件内容变化触发ElForm重新校验

对于下图中“付费类型”怎么实现有很多种方式&#xff0c;我能想到的是以下两种&#xff1a; Element Plus的RadioButton自定义组件 1. RadioButton 它本质上就是一个单选组件&#xff0c;它跟Element Plus的RadioButton本质上没有区别&#xff0c;无非是外观上的差别。那么…