[MySQL]MySQL数据类型
资料引用:
《高性能MySQL》
本文包括MySQL基本数据类型的说明与选用原则说明、Java的字段映射。欢迎讨论。
目录
基本数据类型
整数类型
整数类型案例
实数类型
字符串类型
枚举类型
日期类型
时间类型案例
位压缩数据类型
BIT
JSON数据类型
MySQL行大小限制
Java数据类型与MySql数据类型对照表
补充-布尔值与tinyint
补充-时间类型处理
补充-枚举类型
MySQL数据类型别名支持
MyBatis字段映射原理
数据类型区别
Varchar与Varchar2区别:
Mysql varchar
标识符的选择
整数类型标识符
字符串类型标识符
补充-生产遇到的字符串类型主键
UUID问题汇总(适应所有类型随机值)
问题汇总
补充-有序UUID
高并发时主键设计
雪花算法Snowflake Algorithm
分布式ID生成器
分布式数据库的主键策略
Redis生成ID
Zookeeper生成唯一ID
更好的数据类型(类型选择原则)
更小的通常更好(慷慨是不明智的)
简单为好
尽量避免存储NULL
特殊数据类型
IP
基本数据类型
整数类型
整数类型案例
使用整数类型存储IP地址。
实数类型
字符串类型
对于短字符串,CHAR比VARCHAR更高效,因为存储内容时不需要记录长度的额外字节,对于经常修改的数据,CHAR也不容易出现碎片。
CHAR固定长度,最大255,但是CHAR类型末尾的空格会被删除。
枚举类型
可以使用枚举类型ENUM代替常规字符串类型。
MySQL枚举类型存储一组定义不同的字符串值,这一组值在内部保存为整数,这样可以让列更小以节省开销。
但是因为CHAR|VARCHAR类型列连接到ENUM列可能比联接到另一个CHAR|VARCHAR列更慢。
所以需要根据实际情况使用ENUM枚举类型。
日期类型
DATETIME和TIMESTAMP都可以同时存储日期和时间。
DATETIME需要8字节空间,指定时间格式,ANSI表示方式显示值。
注意小写的 yyyy 用于表示“年份(Year)”,它指的是日历年份。大写的 YYYY 则用于表示“周年代(Week Year)”。
TIMESTAMP需要4字节空间,同UNIX时间戳。但是范围小得多:只能表示到2038年1月19日。
时间戳的显示依赖时区,MySQL服务器、操作系统和客户端连接都有时区设置。
时间类型案例
将日期和时间存储为MySQL的内置类型而不是字符串型;
DATETIME和TIMESTAMP列可以存储相同类型的数据:时间和日期,精确到秒,然而TIMESTAMP可以随时区变化,有特殊的自动更新能力。另一方面,TIMESTAMP允许的时间范围要小得多,有时候它得特殊能力为成为障碍。
位压缩数据类型
BIT
JSON数据类型
MySQL支持JSON类型数据直接存储,且使用更多的空间来存储用于定义JSON的额外字符(大括号、方括号、冒号等)以及空格。
可以通过表达式直接查询JSON列中的json属性值,但是性能上JSON列查询速度低于将JSON作为表查询(微小差距,数据每天被访问数百万次累计才有明显差异)。
总的来说,决定使用原生SQL还是JSON取决于在数据库中存储JSON的便捷性是否大于性能。
MySQL行大小限制
VARCHAR类型可变长度,但在MySQL中,单行最大大小被限制为65535字节,即64KB。
这64KB包括所有列的数据、数据行格式、行头信息等额外开销,但不包括TEXT类型与BLOB类型。
所以,设计VARCHAR类型时需要注意使用的字符集和字符串长度,注意整行不要超过65535字节。
Java数据类型与MySql数据类型对照表
类型名称 | 显示长度 | 数据库类型 | JAVA类型 | JDBC类型索引(int) |
VARCHAR | L+N | VARCHAR | java.lang.String | 12 |
CHAR | N | CHAR | java.lang.String | 1 |
BLOB | L+N | BLOB | java.lang.byte[] | -4 |
TEXT | 65535 | VARCHAR | java.lang.String | -1 |
INTEGER | 4 | INTEGER UNSIGNED | java.lang.Long | 4 |
TINYINT | 3 | TINYINT UNSIGNED | java.lang.Integer | -6 |
SMALLINT | 5 | SMALLINT UNSIGNED | java.lang.Integer | 5 |
MEDIUMINT | 8 | MEDIUMINT UNSIGNED | java.lang.Integer | 4 |
BIT | 1 | BIT | java.lang.Boolean | -7 |
BIGINT | 20 | BIGINT UNSIGNED | java.math.BigInteger | -5 |
FLOAT | 4+8 | FLOAT | java.lang.Float | 7 |
DOUBLE | 22 | DOUBLE | java.lang.Double | 8 |
DECIMAL | 11 | DECIMAL | java.math.BigDecimal | 3 |
BOOLEAN | 1 | 同TINYINT | ||
ID | 11 | PK (INTEGER UNSIGNED) | java.lang.Long | 4 |
DATE | 10 | DATE | java.sql.Date | 91 |
TIME | 8 | TIME | java.sql.Time | 92 |
DATETIME | 19 | DATETIME | java.sql.Timestamp | 93 |
TIMESTAMP | 19 | TIMESTAMP | java.sql.Timestamp | 93 |
YEAR | 4 | YEAR | java.sql.Date | 91 |
补充-布尔值与tinyint
java Boolean对应tinyint (1) ,如果tinyint字段的结果只有0或者1,那么使用Boolean,其他情况使用Integer
MyBatis 在将数据库中的数据映射回 Java 对象时,会自动将 TINYINT(1) 类型的数据转换成布尔值。具体来说,0 会被视为 false,而 1 被视为 true。
但是,如果查询返回多条记录且记录数大于 1,则返回的布尔值将是 false 。
补充-时间类型处理
Mysql使用 DateTime来处理到秒的时间 ——yyyy-MM-dd HH:mm:ss
可以使用Date和LocalDateTime接收
使用 MyBatis 框架时,MySQL 的 DATETIME 或 TIMESTAMP 类型可以映射到 Java 的 LocalDateTime 类型。
MyBatis 3.4.5 或更高版本,默认情况下已经支持了这些类型的映射。版本之前,需要JSR
补充-枚举类型
枚举类型通常对应Java中的String
MySQL数据类型别名支持
INTEGER,映射到INT
BOOL,映射到TINYINT,0false
UNMERIC,映射到DECIMAL
MyBatis字段映射原理
手动映射如resultMap,自动映射-名称对应
数据类型区别
Varchar与Varchar2区别:
varchar2是oracle专属数据类型,长度为4000,将空串作为null处理
Mysql varchar
4.1之前为字节、5.0之后版本为字符
标识符的选择
标识符类型确认后,需要确保所有关联的表都使用相同类型,且包括UNSIGNED等属性完全匹配。
混合不同类型数据可能导致性能问题,或者产生难以发现的错误。
整数类型标识符
速度快,可以自动递增。但是可能会意外耗尽整数,需要确保数据增长预计适合整数大小。
字符串类型标识符
比整数耗空间、慢。使用MD5或者UUID作为标识的字符串会任意分布在很大的空间内,会减慢insert和部分select查询的速度。
补充-生产遇到的字符串类型主键
有限的工作经验的补充。
UUID遇到的很少,且几乎都没有取出破折号-后使用UNHEX()函数将UUID转换成二进制表达式存储的,都是直接存储。
当然,这样查询速度慢。
但是在生产中,只感受到了UUID带来运维的问题,不知道这个UUID是哪个表的,什么业务的,什么时间的。
生产中常见的字符串类型主键,一般都使用了额外的标识位来标识业务类型、业务状态、数据库标识、时间,很长,但是很利于运维与排查问题。
UUID问题汇总(适应所有类型随机值)
问题汇总
没什么业务意义,UUID列作为聚簇索引时,其插入完全随机,插入花费的时间更长,且占用空间更大。
一方面是UUID更长,另一方面是随机插入导致的页分裂和碎片导致的。
UUID在插入索引时,因为随机导致的无序,需要重新计算位置并分配空间,并导致数据分布不够优化。
补充-有序UUID
一种改进型UUID,Java有工具类可以生成。
MySQL8.0及以上版本也支持有序UUID。
高并发时主键设计
在高并发时,主键顺序插入会变得更糟。UUID本身性能就差。因此,分布式高并发情况下,可以考虑的主键(标识)方案如下:
雪花算法Snowflake Algorithm
雪花算法能生成有序、全局唯一的序列号。
分布式ID生成器
第三方工具
分布式数据库的主键策略
分布式数据库系统通常内置了处理全局唯一ID的功能。
Redis生成ID
通过Redis的原子操作特性,可以在分布式环境中安全地生成不重复的ID。
Zookeeper生成唯一ID
zk通过临时时序节点的方式生成唯一ID
更好的数据类型(类型选择原则)
更小的通常更好(慷慨是不明智的)
更小的数据类型通常更快。但是也要确保没有低估存储的值的范围
简单为好
简单数据类型的操作通常需要更少的CPU周期。
例如:整型数据比字符型数据的比较操作代价更低,因为字符集和排序规则使字符型数据的比较更复杂。
尽量避免存储NULL
除非明确需要存储NULL值,通常最好为NOT NULL。
因为包含NULL的列对于MySQL来说更难优化,可为NULL的列使得索引、索引统计和值的比较都更复杂。可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。
但是改为NOT NULL性能提升比较小,除非确认会导致问题,否则不用修改现有表结构以防止出现问题。
特殊数据类型
IP
使用整数来存储IP