前言
这篇文章,一起简单了解下~ mysql 整形、字符串类型、时间戳类型、JSON类型的使用场景和坑
整形的坑
整形分成很多种,TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT
类型 | 占用空间(字节) | 值范围(signed) | 值范围(unsigned) |
---|---|---|---|
TINYINT | 1 | -128~127 | 0~255 |
SMALLINT | 2 | -32768~32767 | 0~65535 |
MEDIUMINT | 3 | -838608~8388607 | 0~16777215 |
INT | 4 | -2147483638~2147483637 | 0~4294967295 |
BIGINT | 8 | -9223372036854775808~9223372036854775807 | 0~18446744073709551615 |
业务设计
-
不推荐使用整型类型的属性 Unsigned
,若非要使用,参数 sql_mode 务必额外添加上选项 NO_UNSIGNED_SUBTRACTION- 因为 unsigned 和非unsigned 做操作,如果结果是负数,会报错
-
自增整型类型做主键,务必使用类型 BIGINT
,而非 INT,后期表结构调整代价巨大; -
自增整型回溯问题
: MySQL 8.0 版本前,重启数据库会导致自增回溯,推荐字符串类型做主键
-
当达到自增到上限,再次自增插入,MySQL 数据库会报重复错误;
-
不要再使用浮点类型 Float、Double,
MySQL 后续版本将不支持Float Double两种类型
; -
账户余额字段,单位可以是分,设计是用整型类型,而不是 DECIMAL 类型
,这样性能更好,存储更紧凑。因为DECIMAL 是个变长字段
,会导致读取效率低
、空间碎片化
两个问题
字符串类型
mysql 字符串的定义,包括字符长度类型(varchar/char)
、字符集(UTF8 UTF8MB4)
、排序规则
三部分组成。
VARCHAR 和CHAR
在 MySQL 数据库下,绝大部分场景使用类型 VARCHAR 就足够。CHAR是定长,VARCHAR是可变长度的
字符集
- 推荐
字符集设置为 UTF8MB4
,兼容emoji😯
排序规则
- utf8mb4_0900_ai_ci
- utf8mb4_0900_as_cs
- utf8mb4_bin
排序规则以 _ci 结尾,表示不区分大小写(Case Insentive),_cs 表示大小写敏感,_bin 表示通过存储字符的二进制进行比较。需要注意的是,比较 MySQL 字符串,默认采用不区分大小的排序规则
业务设计
有限状态列设计
一般业务会用tinyint,比如订单状态(待支付、支付中、支付完成、支付取消、已退款等)
但tinyint的缺点是,可能会被插入无效数据,不能准确的限制状态集合。
解决:
mysql5.6,可以用ENUM枚举类型去限制,但这个类型并不符合通用的mysql规范,其他DB没有,迁移时可能会有坑.
mysql8.0解决了这个问题,可以用CHECK约束状态集。
账户密码存储设计
重要!:密码不能明文在DB中存储 ,一般都需要加密后存储,但即使是md5这种单向加密,也是可能被暴力破解的。因此需要加动态salt值
好的密码设计 = 动态盐 + 非固定加密算法 $password格式:
密码设计
$salt$cryption_algorithm$value(加密后的字符串)
动态salt,一般结合时间戳、随机数、用户信息去生成,也需要持久化到DB里.
日期类型字段设计
mysql常用的日期类型,是DATETime
和TIMESTAMP
。
DATETIME
类型 DATETIME 最终展现的形式为:YYYY-MM-DD HH:MM:SS,固定占用 8 个字节。
我们可以在表上设置DATETIME
,并保证update当前行时,自动更新日期
Mysql
last_modify_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6)
对应到Golang代码里,就是time.Time类型的字段:
Golang
type Data struct{
LastModifyDate time.Time `gorm:"last_modify_date"`
}
TIMESTAMP
TIMESTAMP
也是时间类型,但他自带了时区信息。
TIMESTAMP的坑
:由于类型 TIMESTAMP 占用 4 个字节,因此其存储的时间上限只能到'2038-01-19 03:14:07'。
业务选型:DATETIME
、TIMESTAMP
、INT
建议使用DATETIME
- MySQL 5.6 版本开始 DATETIME 和 TIMESTAMP 精度支持到毫秒;
- DATETIME 占用 8 个字节,TIMESTAMP 占用 4 个字节,DATETIME(6) 依然占用 8 个字节,TIMESTAMP(6) 占用 7 个字节;
- TIMESTAMP 日期存储的上限为 2038-01-19 03:14:07,业务用 TIMESTAMP 存在风险;
- 推荐日期类型使用 DATETIME,而不是 TIMESTAMP 和 INT 类型;
- 表结构设计时,每个核心业务表,推荐设计一个 last_modify_date 的字段,用以记录每条记录的最后修改时间。
JSON字段设计
在关系存储中,有一些非结构化的数据,虽然也可以按照关系型去存储,但可能会导致两个问题:
数据非常稀疏
可扩展性差
比如这样的JSON:
json
{
"qq_number":123
"wx_number":123
...
"xx_number"
}
数据稀疏问题
:比如用户绑定了qq、微信、微博等平台,实际业务允许只绑定任意一个.大部分列就会是空的,数据稀疏
扩展性差
:如果现在要扩一个新平台字段,再增加一列,还需要修改表结构
这时候JSON的好处就体现了. 可以既不修改表结构,又解决数据稀疏的问题。
JSON字段使用总结
JSON 类型是 MySQL 5.7 版本新增的数据类型
- 使用 JSON 数据类型,需要用 MySQL 8.0.17 以上的版本,性能更好,同时也支持 Multi-Valued Indexes,即一列里存储多种值,可以根据单个值索引;
- JSON 数据类型的好处是无须预先定义列;
- 不要将有明显关系型的数据用 JSON 存储,如用户余额、用户姓名、用户身份证等,这些都是每个用户必须包含的数据;
- JSON 数据类型推荐使用在不经常更新的静态数据存储。