每天学习一点点之 MySQL TINYINT
我已经不是第一次遇到关于 TINYINT 的问题了。在 MySQL 中,当我们将某个字段设置为 TINYINT,随着业务的扩展,我们可能会发现 TINYINT 的范围无法满足需求。这时需要修改字段属性。但如果表的数据量很大,或者由于分表导致涉及的表数量众多,这个过程可能会变得比较复杂。更糟糕的是,如果代码中的数据类型为 int,而 MySQL 中的数据类型为 TINYINT,可能会导致存储异常数据。
这里把 MySQL 整数类型做个总结:
| 类型名称 | 翻译 | 空间占用 | 范围(有符号) | 范围(无符号) |
|---|---|---|---|---|
| TINYINT | 很小的整数 | 1个字节 | -128〜127 | 0 〜255 |
| SMALLINT | 小的整数 | 2个宇节 | -32768〜32767 | 0〜65535 |
| MEDIUMINT | 中等大小的整数 | 3个字节 | -8388608〜8388607 | 0〜16777215 |
| INT (INTEGHR) | 普通大小的整数 | 4个字节 | -2147483648〜2147483647 | 0〜4294967295 |
| BIGINT | 大整数 | 8个字节 | -9223372036854775808〜9223372036854775807 | 0〜18446744073709551615 |
TINYINT 与 INT:空间节省的实际影响
如上表所示,使用 TINYINT 替代 INT 可以节省 3 字节的存储空间。
换句话说,如果你有一个包含 1,000,000 行的表,并且其中有一个 INT 类型的列。将此列更改为 TINYINT,将大约节省 3MB 的存储空间(1,000,000 行 * 3 字节/行 = 3,000,000 字节 ≈ 3MB)。但这种节省在大多数情况下可能并不会带来显著的性能提升或成本降低。
何时应考虑使用 TINYINT
对于这个问题,我认为没有必要过于纠结,也没有绝对的答案。
有时候,我们选择使用 TINYINT 主要是出于教条式的成本考虑,但如前所述,这种成本差异几乎可以忽略。因此,决定何时使用 TINYINT,我们只需要考虑其范围是否满足当前业务需求以及可能的未来发展。
例如,如果你需要添加一个表示性别或者 true/false 的字段,这种情况下,数据范围较小,且不可能超过 TINYINT 的范围,那么使用 TINYINT 是合适的。然而,对于如订单来源或状态等可能会发生变化的字段,我们需要更加谨慎,因为这些场景是典型的随着业务的发展可能会修改 TINYINT 字段的情况,这也是我在实际工作中遇到的最常见的场景。
解读公司内部《MySQL开发规范》
公司内部的《MySQL开发规范》 中有这么一段说明:
禁止使用tinyint ,在JAVA环境有转换问题。区分使用TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT数据类型和取值范围(TINYINT>SMALLINT>MEDIUMINT>INT>BIGINT>DECIMAL—存储空间逐渐变大,而性能却逐渐变小)。
禁止使用 TINYINT
这个问题的关键在于 MySQL 中的 TINYINT 类型和 Java 中的数据类型之间的映射关系。
先看一个例子:
package blog.dongguabai.others.mysql_tinyint;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;/*** @author dongguabai* @date 2023-11-30 00:27*/
public class Test {public static String url = "jdbc:mysql://10.224.221.151:3306/test_1";public static String user = "root";public static String password = "root";public static void main(String[] args) {try (Connection conn = DriverManager.getConnection(url, user, password);Statement stmt = conn.createStatement()) {stmt.execute("DROP TABLE IF EXISTS tinyint_test");stmt.execute("CREATE TABLE tinyint_test (id TINYINT UNSIGNED, id_signed TINYINT, id_boolean TINYINT(1))");stmt.execute("INSERT INTO tinyint_test VALUES (255, -128, 1)");try (ResultSet rs = stmt.executeQuery("SELECT * FROM tinyint_test")) {while (rs.next()) {System.out.println("id: " + rs.getObject("id").getClass().getName());System.out.println("id_signed: " + rs.getObject("id_signed").getClass().getName());System.out.println("id_boolean: " + rs.getObject("id_boolean").getClass().getName());}}} catch (SQLException e) {e.printStackTrace();}}
}
输出结果:
id: java.lang.Integer
id_signed: java.lang.Integer
id_boolean: java.lang.Boolean
可以得出如下结论:
-
TINYINT转换为Integer在 MySQL 中,
TINYINT是一个 8 位的整数,可以是有符号的(取值范围 -128 到 127)或无符号的(取值范围 0 到 255)。在 Java 中最接近的类型是byte,也是 8 位的,但它是有符号的,取值范围是 -128 到 127。这意味着TINYINT的取值范围可能超过了 JavaByte类型的取值范围。因此,JDBC 默认将TINYINT类型转换为 Java 的Integer类型,而不是Byte类型 -
TINYINT(1)转换为Boolean在 MySQL 中,
TINYINT(1)通常用于表示布尔值,JDBC 将其转换为 Java 的Boolean类型。(可以在 JDBC 连接字符串中添加
tinyInt1isBit=false参数,这样TINYINT(1)就不会被转换为Boolean,而是和其他TINYINT类型一样被转换为Integer)
原理可以从 com.mysql.cj.jdbc.result.ResultSetImpl#getObject(int) 中找到:
@Overridepublic Object getObject(int columnIndex) throws SQLException {...Field field = this.columnDefinition.getFields()[columnIndexMinusOne];switch (field.getMysqlType()) {//TINYINT(1)转化为 BITcase BIT:// TODO Field sets binary and blob flags if the length of BIT field is > 1; is it needed at all?if (field.isBinary() || field.isBlob()) {byte[] data = getBytes(columnIndex);if (this.connection.getPropertySet().getBooleanProperty(PropertyKey.autoDeserialize).getValue()) {Object obj = data;if ((data != null) && (data.length >= 2)) {if ((data[0] == -84) && (data[1] == -19)) {// Serialized object?try {ByteArrayInputStream bytesIn = new ByteArrayInputStream(data);ObjectInputStream objIn = new ObjectInputStream(bytesIn);obj = objIn.readObject();objIn.close();bytesIn.close();} catch (ClassNotFoundException cnfe) {throw SQLError.createSQLException(Messages.getString("ResultSet.Class_not_found___91") + cnfe.toString()+ Messages.getString("ResultSet._while_reading_serialized_object_92"), getExceptionInterceptor());} catch (IOException ex) {obj = data; // not serialized?}} else {return getString(columnIndex);}}return obj;}return data;}return field.isSingleBit() ? Boolean.valueOf(getBoolean(columnIndex)) : getBytes(columnIndex);case BOOLEAN:return Boolean.valueOf(getBoolean(columnIndex));//TINYINT 转化为 Integercase TINYINT:return Integer.valueOf(getByte(columnIndex));case TINYINT_UNSIGNED:case SMALLINT:case SMALLINT_UNSIGNED:case MEDIUMINT:case MEDIUMINT_UNSIGNED:case INT:return Integer.valueOf(getInt(columnIndex)); //TINYINT_UNSIGNED 转化为 Integer
...
}
这里要注意数据库字段设置为 TINYINT(1) 在 columnDefinition 会被映射为 MysqlType.BIT。
存储空间逐渐变大,而性能却逐渐变小
存储空间和性能之间的关系可以从两个方面来理解:
-
存储空间:
TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT这些类型的存储空间从小到大排列。这是因为它们能表示的数值范围也是从小到大的。例如,TINYINT只需要 1 字节就可以表示 -128 到 127 的整数,而BIGINT需要 8 字节来表示更大范围的整数。 -
性能:当我们说性能逐渐变小,我们是指处理更大的数据类型通常需要更多的 CPU 时间和内存。例如,读取和写入一个
BIGINT值通常会比读取和写入一个TINYINT值需要更多的时间。这是因为处理更大的数据需要更多的计算资源。但这些不同的整数类型在性能上的差异是微不足道的。这是因为现代的 CPU 和内存都足够快了。
References
- MySQL开发规范(内网)
欢迎关注公众号:

相关文章:
每天学习一点点之 MySQL TINYINT
我已经不是第一次遇到关于 TINYINT 的问题了。在 MySQL 中,当我们将某个字段设置为 TINYINT,随着业务的扩展,我们可能会发现 TINYINT 的范围无法满足需求。这时需要修改字段属性。但如果表的数据量很大,或者由于分表导致涉及的表数…...
【数据集】未来不同情景下预测数据:如人口、土地利用等
未来不同情景下预测数据:如人口、土地利用等 1 人口数据1.1 Global One-Eighth Degree Population Base Year and Projection Grids Based on the SSPs, v1.01 (2000 – 2100)数据介绍数据下载1.2 Global dataset of gridded population and GDP scenarios数据介绍数据下载2…...
TDA4VM EVM开发板调试笔记
文章目录 1. 前言2. 官网资料导读3. 安装 Linux SDK4. 制作SD 启动卡5. 验证启动1. 前言 TDA4作为一般经典的车规级SOC芯片,基于它的低阶智驾方案目前成为各家智驾方案公司的量产首选,这也使得基于TDA4的开发需求陡增,开发和使用TDA4既要熟悉Linux驱应用开发,还要熟悉传统…...
项目里边更换了同名的图片地址 / 图片没有及时更新 / 什么原因
一、问题分析 1.1、分析一 浏览器缓存 项目里边更换了同名的图片地址,图片没有及时更新 可能是浏览器缓存的原因,浏览器会将之前访问过的文件缓存下来,下次访问同名的文件时会先从缓存中读取。 如果相同的图片地址没有发生变化,…...
RandomAccessFile学习笔记
文章目录 RandomAccessFile学习笔记前言1、RandomAccessFile基本介绍1.1 RandomAccessFile相关基本概念1.2 RandomAccessFile家族体系 2、RandomAccessFile基本使用2.1 RandomAccessFile常用API介绍2.2 RandomAccessFile常用API演示2.3 RandomAccessFile实现断点续传 RandomAcc…...
主流数据库类型总结
前言:随着互联网的高速发展,为了满足不同的应用场景,数据库的种类越来越多容易混淆,所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值(Key-…...
程序员养生之道
程序员养生之道——如何保持健康的生活方式 摘要: 随着互联网行业的快速发展,越来越多的人选择从事程序员这个职业。然而,长时间的工作和高强度的压力容易导致程序员出现亚健康状况,如头发稀疏、视力下降、肥胖等问题。因此&#…...
CNN对 MNIST 数据库中的图像进行分类
加载 MNIST 数据库 MNIST 是机器学习领域最著名的数据集之一。 它有 70,000 张手写数字图像 - 下载非常简单 - 图像尺寸为 28x28 - 灰度图 from keras.datasets import mnist# 使用 Keras 导入MNIST 数据库 (X_train, y_train), (X_test, y_test) mnist.load_data()print(&…...
HarmonyOS开发工具简介
工具简介 更新时间: 2023-10-13 11:06 分享 添加收藏 说明 该文档匹配DevEco Studio 3.1.1 Release版本。 概述 HUAWEI DevEco Studio(获取工具请单击链接下载,以下简称DevEco Studio)是基于IntelliJ IDEA Community开源版本打造,…...
大量索引场景下 Easysearch 和 Elasticsearch 的吞吐量差异
最近有客户在使用 Elasticsearch 搜索服务时发现集群有掉节点,并且有 master 收集节点信息超时的日志,节点的负载也很高,不只是 data 节点,master 和协调节点的 cpu 使用率都很高,看现象集群似乎遇到了性能瓶颈。 查看…...
东明石化集团领导团队参访震坤行工业超市
东明石化集团领导团队参访震坤行工业超市 10月16日,山东东明石化集团(以下简称东明石化)总裁李治先生一行带队来访参观交流震坤行,与震坤行工业超市董事长兼CEO陈龙、销售负责团队开展座谈。期间,双方就企业数字化转型…...
Java常见的面试题(很基础那种)
这里介绍一下,一些比较基础的Java面试题,比较适合应届生、实习生这些朋友。因为对于刚出来工作的Java工程师,很多企业都偏向招一些基础比较好的苗子回来培养。所以啊,在校的朋友们,一定要在读书期间,多做项目,如果没有实际的项目,可以在github找一些案例来做参考,先模…...
MySQL处理并发访问和高负载的关键技术和策略
我深知在数据库管理中处理并发访问和高负载的重要性。在这篇文章中,我将探讨MySQL处理并发访问和高负载的关键技术和策略,以帮助读者更好地优化数据库性能。 图片来源:MySQL处理并发访问和高负载的关键技术和策略 MySQL数据库在处理并发访问…...
软件测试jmeter基本使用
1安装与配置 1.jdk下载 下载地址:https://www.oracle.com/java/technologies/downloads/#jdk18-windows(压缩包中会给) 2.jmeter下载 Apache JMeter - Download Apache JMeter(压缩包中有) 3.操作教学 打开软件后新…...
一文讲透Python函数中的局部变量和全局变量
变量的作用域就是变量能够发挥作用的区域,超出既定区域后就无法发挥作用。根据变量的作用域可以将变量分为局部变量和全局变量。 1.局部变量 局部变量是在函数内部定义并使用的变量,也就是说只有在函数内部,在函数运行时才会有效࿰…...
【LeetCode】每日一题 2023_11_23 HTML 实体解析器(调库/打工)
文章目录 刷题前唠嗑题目:HTML 实体解析器题目描述代码与解题思路 结语 刷题前唠嗑 题目:HTML 实体解析器 题目链接:1410. HTML 实体解析器 题目描述 代码与解题思路 func entityParser(s string) (ans string) {return strings.NewRepla…...
Flask SocketIO 实现动态绘图
Flask-SocketIO 是基于 Flask 的一个扩展,用于简化在 Flask 应用中集成 WebSocket 功能。WebSocket 是一种在客户端和服务器之间实现实时双向通信的协议,常用于实现实时性要求较高的应用,如聊天应用、实时通知等,使得开发者可以更…...
软著项目推荐 深度学习 植物识别算法系统
文章目录 0 前言2 相关技术2.1 VGG-Net模型2.2 VGG-Net在植物识别的优势(1) 卷积核,池化核大小固定(2) 特征提取更全面(3) 网络训练误差收敛速度较快 3 VGG-Net的搭建3.1 Tornado简介(1) 优势(2) 关键代码 4 Inception V3 神经网络4.1 网络结构 5 开始训练5.1 数据集…...
自动驾驶HWP 功能规范
目 录 概述 1 目的 1范围 1术语及缩写 1设计与实验标准 1 设计标准 2设计标准执行优先顺序 2功能规范 Specification 4 功能描述 Functional Description 4 工作条件与应用范围 Application Scope 4道路交通 4天气与光线 4传感器方案及需求 5 驾驶员状态监控系统 5前视摄像…...
Ubuntu 环境下 NFS 服务安装及配置使用
需求:公司内部有多台物理服务器,需要A服务器上的文件让B服务器访问,也就是两台服务器共享文件,当然也可以对A服务器上的文件做权限管理,让B服务器只读或者可读可写 1、NFS 介绍 NFS 是 Network FileSystem 的缩写&…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
