每天学习一点点之 MySQL TINYINT

我已经不是第一次遇到关于 TINYINT 的问题了。在 MySQL 中,当我们将某个字段设置为 TINYINT,随着业务的扩展,我们可能会发现 TINYINT 的范围无法满足需求。这时需要修改字段属性。但如果表的数据量很大,或者由于分表导致涉及的表数量众多,这个过程可能会变得比较复杂。更糟糕的是,如果代码中的数据类型为 int,而 MySQL 中的数据类型为 TINYINT,可能会导致存储异常数据。

这里把 MySQL 整数类型做个总结:

类型名称翻译空间占用范围(有符号)范围(无符号)
TINYINT很小的整数1个字节-128〜1270 〜255
SMALLINT小的整数2个宇节-32768〜327670〜65535
MEDIUMINT中等大小的整数3个字节-8388608〜83886070〜16777215
INT (INTEGHR)普通大小的整数4个字节-2147483648〜21474836470〜4294967295
BIGINT大整数8个字节-9223372036854775808〜92233720368547758070〜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

可以得出如下结论:

  1. TINYINT 转换为 Integer

    在 MySQL 中,TINYINT 是一个 8 位的整数,可以是有符号的(取值范围 -128 到 127)或无符号的(取值范围 0 到 255)。在 Java 中最接近的类型是 byte,也是 8 位的,但它是有符号的,取值范围是 -128 到 127。这意味着 TINYINT 的取值范围可能超过了 Java Byte 类型的取值范围。因此,JDBC 默认将 TINYINT 类型转换为 Java 的 Integer 类型,而不是 Byte 类型

  2. 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

存储空间逐渐变大,而性能却逐渐变小

存储空间和性能之间的关系可以从两个方面来理解:

  1. 存储空间:TINYINTSMALLINTMEDIUMINTINTBIGINT 这些类型的存储空间从小到大排列。这是因为它们能表示的数值范围也是从小到大的。例如,TINYINT 只需要 1 字节就可以表示 -128 到 127 的整数,而 BIGINT 需要 8 字节来表示更大范围的整数。

  2. 性能:当我们说性能逐渐变小,我们是指处理更大的数据类型通常需要更多的 CPU 时间和内存。例如,读取和写入一个 BIGINT 值通常会比读取和写入一个 TINYINT 值需要更多的时间。这是因为处理更大的数据需要更多的计算资源。

    但这些不同的整数类型在性能上的差异是微不足道的。这是因为现代的 CPU 和内存都足够快了。

References

  • MySQL开发规范(内网)

欢迎关注公众号:
在这里插入图片描述

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

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

相关文章

ARM安全架构——为复杂软件提供保护

目录 一、概述 二、栈溢出和执行权限 三、面向返回的编程ROP 四、面向跳转的编程(JOP) 五、将这些技术应用于实际代码 七、检查你的知识

java+springboot物流管理系统设计与实现wl-ssmj+jsp

物流管理系统的开发和综合性的物流信息网站平台的建设。研究的重点是运输管理信息系统.本系统是一套基于运输作业流程的管理系统,该系统以运输任务、货品、商务三大线索设计开发。运输任务是该管理系统的核心,系统通过对运输任务中的接收、调…

Linux C语言 36-文件处理补充

Linux C语言 36-文件处理补充 本节关键字:C语言 文件操作,文件处理,文件创建,文件信息,文件删除,目录创建,目录信息,目录遍历,目录递归遍历 相关C库函数:acc…

[cocos creator]EditBox,editing-return事件,清空输入框

需求: 监听EditBox,editing-return 回车事件,在输入框内点击回车后,发送内容,并清空输入框 问题: 设置node.getComponent(EditBox).string ; 没有效果 解决办法: //设置string 为空 this.v…

应用程序APP制作用Vue3CreateApp打包有什么优势?有哪些好处?

在当代的前端开发领域,Vue.js作为一个领先的JavaScript框架,一直处于技术革新和发展的前沿。Vue3作为该框架的最新版本,带来了更多的新特性和优化。在这些新特性中,createApp方法是一个非常值得关注的变化。对于开发者而言&#x…

osg demo汇总

1.example_osganimate 演示了路径动画的使用(AnimationPath、AnimationPathCallback),路径动画回调能够做用在Camera、CameraView、MatrixTransform、PositionAttitudeTransform等四种类型的节点上。 演示了osgSim::OverlayNode的使用node 2…

[操作系统] 大厂必问~虚拟内存系列

文章目录 4.1 什么是虚拟内存(Virtual Memory)?4.2 局部性原理4.3 虚拟存储器4.4 虚拟内存的技术实现4.5 页面置换算法OPT 页面置换算法(最佳页面置换算法)FIFO(First In First Out) 页面置换算法(先进先出页面置换算…

MyBatis教程之逆向工程(十一)

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程 的。逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源: 1.Java实体类 2.Mapper…

使用easyExcel框架报错:服务器缺少字体

后台服务使用easyExcel框架生成表格,但是生成的时候报如下的错误: 这种报错其实就是部署服务的服务器缺少字体,正确的方法是安装字体。需要注意的是,测试环境服务器与生产环境服务器的在配置版本上可能存在差异,因此需…

初识Java 18-6 泛型

目录 潜在类型机制 支持潜在类型机制的语言 Python的潜在类型机制 C的潜在类型机制 Java中的直接潜在类型机制 潜在类型机制的替代方案 反射 将方法应用于序列中的每个元素 Java 8的潜在类型机制(间接实现) 潜在类型机制的使用例(S…

『 MySQL数据库 』CRUD之UD,表的数据更新(修改)及删除

文章目录 🥩 Update (更新/修改) 🦖🥚 修改单行数据的某个字段内的数据 🦕🥚 配合LIMIT分页与ORDER BY 对符合条件的多条数据进行修改 🦕🥚 对整表的某个数据字段进行修改 🦕 &#…

MySQL--锁

锁 锁是mysql在并发访问时,解决数据访问一致性、有效性的一种机制 mysq中的锁,按照锁的粒度分,分为以下三类: 全局锁:锁定数据库中的所有表 表级锁:每次操作锁住整张表 行级锁:每次操作锁住对…

Android 架构实战MVI进阶

MVI架构的原理和流程 MVI架构是一种基于响应式编程的架构模式,它将应用程序分为四个核心组件:模型(Model)、视图(View)、意图(Intent)和状态(State)。 原理&…

【AntDB数据库】国产数据库崛起之狂飙猛进的互联网技术

中国作为人口大国,也是重要的人才资源大国,人口大国带来了国外数据库厂商在世界其他国家不曾出现的高复杂高密度的需求场景,而人才资源大国则让我们在互联网尤其是移动互联网方面奋起直追,甚至达到了全球领先的水平,进…

JS的原生函数

JS的原生函数,包括:String()、Number()、Boolean()、Array()、Object()、Function()、RegExp(&…

通过navicat工具将excel文件导入数据库的表中

文章目录 1.navicat可视化工具2. 导入文件 1.navicat可视化工具 这里使用的是navicat数据库可视化工具,不是直接通过数据库指令导入的 前提是连接好数据库,建立好表,如下图,test为连接名,随便起,data为数据…

学习程序员必知必会的基础算法(收藏)

近年来学习python的程序员愈来愈多,有的同学选择了python培训机构,也有的人觉得自己天赋好选择了自学不管大家怎么去学习,在学习python基础的过程中,肯定离不开的就是基础算法,今天就为大家介绍几大学习中的基础算法。…

Arkts http数据请求

使用Arkts功能需要申请ohos.permission.INTERNET权限。即在module.json5文件中申明网络访问权限:ohos.permission.INTERNET。如下 {"module" : {"requestPermissions":[{"name": "ohos.permission.INTERNET"}]} } Arkts …

LLM面面观之Prefix LM vs Causal LM

1. 背景 关于Prefix LM和Causal LM的区别,本qiang在网上逛了一翻,发现多数客官只给出了结论,但对于懵懵的本qiang,结果仍是懵懵... 因此,消遣了多半天,从原理及出处,交出了Prefix LM和Causal …

Python requests请求响应以流stream的方式打印输出

如果你使用的请求库是requests,那么你必须了解的大模型里的请求怎么响应式的接收并打印出来的。 这里给大家写一下正式的书写方式: import requestsurl "http://localhost:8080/stream"payload {} headers {}response requests.request("GET&q…