共计 3006 个字符,预计需要花费 8 分钟才能阅读完成。
你好,我是程序员 Alan。
这篇文章我会具体讲一下设计表构造时我会重点关注的中央,助你少走弯路。
数字类型
这里须要重点关注一下范畴,不须要记得十分分明,然而要有一个大略的印象,对边界问题要敏感。
另外不举荐应用数据库的浮点类型,否则在计算时,因为精度类型问题,会导致最终的计算结果出错,这是因为 MySQL 之前的版本中的浮点类型 Float 和 Double,不是高精度。
更重要的是,从 MySQL 8.0.17 版本开始,当创立表用到类型 Float 或 Double 时,会抛出上面的正告:MySQL 揭示用户不该用上述浮点类型,甚至揭示将在之后版本中废除浮点类型。
在理论的开发中,咱们经常会应用整型类型来作为表的主键,即用来惟一标识一行数据。整型联合属性 auto_increment,能够实现 自增性能,但在表结构设计时用自增做主键,心愿你特地要留神以下两点,若不留神,可能会对业务造成灾难性的打击:
- 用 BIGINT 做主键,而不是 INT;
- 自增值并不长久化,可能会有回溯景象(MySQL 8.0 版本前)。
INT 的范畴最大在 42 亿的级别,在实在的互联网业务场景的利用中,一些流水表、日志表,很容易达到最大值。
因而,用自增整型做主键,一律应用 BIGINT,而不是 INT。不要为了节俭 4 个字节应用 INT,当达到下限时,再进行表构造的变更,将是微小的累赘与苦楚。
我所在的公司就遇到过线上环境呈现 INT 类型达到上线导致服务异样的问题,过后运维同学的做法是批改数据库表构造(字段类型 INT -> BIGINT), 你猜这个简略的操作会造成什么问题?表锁死!表锁死又导致了一系列相干申请全副卡死!举个和我的项目无关的例子,助你感受一下问题的严重性,设想一下当初是春运期间,检票进站的时候,检票服务出现异常,大量旅客滞留在候车室的场景
字符串类型
MySQL 数据库的字符串类型我最常应用的是 CHAR、VARCHAR。
CHAR 和 VARCHAR 的定义
CHAR(N) 用来保留固定长度的字符,N 的范畴是 0 ~ 255,请牢记,N 示意的是字符,而不是字节。VARCHAR(N) 用来保留变长字符,N 的范畴为 0 ~ 65536,N 示意字符。
在超出 65536 个字符的状况下,能够思考应用更大的字符类型 TEXT 或 BLOB,两者最大存储长度为 4G,其区别是 BLOB 没有字符集属性,纯属二进制存储。
MySQL 数据库的 VARCHAR 字符类型,最大可能存储 65536 个字符,所以在 MySQL 数据库下,绝大部分场景应用类型 VARCHAR 就足够了。
日期类型
MySQL 数据库中常见的日期类型有 YEAR、DATE、TIME、DATETIME、TIMESTAMEP。因为业务绝大部分场景都须要将日期准确到秒,所以在表结构设计中,常见应用的日期类型为 DATETIME 和 TIMESTAMP。
DATETIME
类型 DATETIME 最终展示的模式为:YYYY-MM-DD HH:MM:SS,固定占用 8 个字节。
从 MySQL 5.6 版本开始,DATETIME 类型反对毫秒,DATETIME(N) 中的 N 示意毫秒的精度。例如,DATETIME(6) 示意能够存储 6 位的毫秒值。同时,一些日期函数也反对准确到毫秒,例如常见的函数 NOW、SYSDATE。
用户能够将 DATETIME 初始化值设置为以后工夫,并设置自动更新以后工夫的属性。
CREATE TABLE User (
id BIGINT NOT NULL AUTO_INCREMENT,
created_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
updated_date DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY(id)
);
TIMESTAMP
除了 DATETIME,日期类型中还有一种 TIMESTAMP 的工夫戳类型,其理论存储的内容为‘1970-01-01 00:00:00’到当初的毫秒数。在 MySQL 中,因为类型 TIMESTAMP 占用 4 个字节,因而其存储的工夫下限只能到‘2038-01-19 03:14:07’。
同类型 DATETIME 一样,从 MySQL 5.6 版本开始,类型 TIMESTAMP 也能反对毫秒。与 DATETIME 不同的是,若带有毫秒时,类型 TIMESTAMP 占用 7 个字节,而 DATETIME 无论是否存储毫秒信息,都占用 8 个字节。
类型 TIMESTAMP 最大的长处是能够带有时区属性,因为它实质上是从毫秒转化而来。如果你的业务须要对应不同的国家时区,那么类型 TIMESTAMP 是一种不错的抉择。比方新闻类的业务,通常用户想晓得这篇新闻公布时对应的本人国家工夫,那么 TIMESTAMP 是一种抉择。
另外,有些国家会执行夏令时。依据不同的节令,人为地调快或调慢 1 个小时,带有时区属性的 TIMESTAMP 类型自身就能解决这个问题。
参数 time_zone 指定了以后应用的时区,默认为 SYSTEM 应用操作系统时区,用户能够通过该参数指定所须要的时区。
DATETIME vs TIMESTAMP vs INT,怎么选?
在做表结构设计时,对日期字段的存储,开发人员通常会有 3 种抉择:DATETIME、TIMESTAMP、INT。
INT 类型就是间接存储 ‘1970-01-01 00:00:00’ 到当初的毫秒数,实质和 TIMESTAMP 一样,因而用 INT 不如间接应用 TIMESTAMP。
当然,有些同学会认为 INT 比 TIMESTAMP 性能更好。然而,因为以后每个 CPU 每秒可执行上亿次的计算,所以毋庸为这种转换的性能放心。更重要的是,在前期运维和数据分析时,应用 INT 存储日期,是会让 DBA 和数据分析人员发疯的,INT 的可运维性太差。
也有的同学会热衷用类型 TIMESTEMP 存储日期,因为类型 TIMESTAMP 占用 4 个字节,比 DATETIME 小一半的存储空间。
但若要将工夫准确到毫秒,TIMESTAMP 要 7 个字节,和 DATETIME 8 字节差不太多。另一方面,当初间隔 TIMESTAMP 的最大值‘2038-01-19 03:14:07’曾经很近,这是须要开发同学好好思考的问题。
总的来说,我倡议你应用类型 DATETIME。 对于时区问题,能够由前端或者服务这里做一次转化,不肯定非要在数据库中解决。
不要漠视 TIMESTAMP 的性能问题
后面曾经提及,TIMESTAMP 的上限值 2038 年很快就会到来,那时业务又将面临一次相似千年虫的问题。另外,TIMESTAMP 还存在潜在的性能问题。
尽管从毫秒数转换到类型 TIMESTAMP 自身须要的 CPU 指令并不多,这并不会带来间接的性能问题。然而如果应用默认的操作系统时区,则每次通过时区计算工夫时,要调用操作系统底层零碎函数 __tz_convert(),而这个函数须要额定的加锁操作,以确保这时操作系统时区没有批改。所以,当大规模并发拜访时,因为热点资源竞争,会产生两个问题。
- 性能不如 DATETIME: DATETIME 不存在时区转化问题。
- 性能抖动: 海量并发时,存在性能抖动问题。
为了优化 TIMESTAMP 的应用,强烈建议你应用显式的时区,而不是操作系统时区。比方在配置文件中显示地设置时区,而不要应用零碎时区.
[mysqld]
time_zone = "+08:00"
站在伟人的肩膀上
- 姜承尧——MySQL 实战宝典
- 菜鸟教程