错误的设计规范:同财务相关的金额类数据必须使用 decimal 类型 由于 float 和 double 都是非精准的浮点数类型,而 decimal 是精准的浮点数类型。所以一般在设计用户余额,商品价格等金融类字段一般都是使用 decimal 类型,可以精确到分。
但是在海量互联网业务的设计标准中,并不推荐用 DECIMAL 类型,而是更推荐将 DECIMAL 转化为整型类型。 也就是说,金融类型更推荐使用用分单位存储,而不是用元单位存储。如1元在数据库中用整型类型 100 存储。
下面是 bigint 类型的优点:
decimal 是通过二进制实现的一种编码方式,计算效率不如 bigint
使用 bigint 的话,字段是定长字段,存储高效,而 decimal 根据定义的宽度决定,在数据设计中,定长存储性能更好
使用 bigint 存储分为单位的金额,也可以存储千兆级别的金额,完全够用
枚举字段的使用错误的设计规范:避免使用 ENUM 类型
在以前开发项目中,遇到用户性别,商品是否上架,评论是否隐藏等字段的时候,都是简单的将字段设计为 tinyint,然后在字段里备注 0 为什么状态,1 为什么状态。
这样设计的问题也比较明显:
表达不清:这个表可能是其他同事设计的,你印象不是特别深的话,每次都需要去看字段注释,甚至有时候在编码的时候需要去数据库确认字段含义
脏数据:虽然在应用层可以通过代码限制插入的数值,但是还是可以通过sql和可视化工具修改值
这种固定选项值的字段,推荐使用 ENUM 枚举字符串类型,外加 SQL_MODE 的严格模式
在MySQL 8.0.16 以后的版本,可以直接使用check约束机制,不需要使用enum枚举字段类型
而且我们一般在定义枚举值的时候使用"Y","N"等单个字符,并不会占用很多空间。但是如果选项值不固定的情况,随着业务发展可能会增加,才不推荐使用枚举字段。
索引个数限制错误的设计规范:限制每张表上的索引数量,一张表的索引不能超过 5 个
MySQL 单表的索引没有个数限制,业务查询有具体需要,创建即可,不要迷信个数限制
子查询的使用错误的设计规范:避免使用子查询
其实这个规范对老版本的 MySQL 来说是对的,因为之前版本的 MySQL 数据库对子查询优化有限,所以很多 OLTP 业务场合下,我们都要求在线业务尽可能不用子查询。
然而,MySQL 8.0 版本中,子查询的优化得到大幅提升,所以在新版本的MySQL中可以放心的使用子查询。
子查询相比 JOIN 更易于人类理解,比如我们现在想查看2020年没有发过文章的同学的数量
SELECT COUNT(*) FROM user WHERE id not in ( SELECT user_id from blog where publish_time >= "2020-01-01" AND publish_time <= "2020-12-31" )可以看到,子查询的逻辑非常清晰:通过 not IN 查询文章表的用户有哪些。
如果用 left join 写
SELECT count(*) FROM user LEFT JOIN blog ON user.id = blog.user_id and blog.publish_time >= "2020-01-01" and blog.publish_time <= "2020-12-31" where blog.user_id is NULL;可以发现,虽然 LEFT JOIN 也能完成上述需求,但不容易理解。
我们使用 explain查看两条 sql 的执行计划,发现都是一样的
通过上图可以很明显看到,不论是子查询还是 LEFT JOIN,最终都被转换成了left hash Join,所以上述两条 SQL 的执行时间是一样的。即,在 MySQL 8.0 中,优化器会自动地将 IN 子查询优化,优化为最佳的 JOIN 执行计划,这样一来,会显著的提升性能。
总结阅读完前面的内容相信大家对 MySQL 已经有了新的认知,这些常见的错误可以总结为以下几点:
UUID 也可以当主键,自增 UUID 比自增主键性能更好,多占用的空间也可忽略不计
金融字段除了 decimal,也可以试试 bigint,存储分为单位的数据
对于固定选项值的字段,MySQL8 以前推荐使用枚举字段,MySQL8 以后使用check函数约束,不要使用 0,1,2 表示
一张表的索引个数并没有限制不能超过5个,可以根据业务情况添加和删除
MySQL8 对子查询有了优化,可以放心使用。