1、数值
1.1、常见的数值类型
MySQL常见的数值类型大致分为如下几种:
tinyint: 2^8 [-128,127] [0,255]
smallint: 2^16 [-32768,32767] [0,65535]
mediuint: 2^24 [-8388608,8388607] [0,16777215]
int: 2^32 [-2147483648,2147483648] [0,4294967295]
bigint: 2^64 unsigned 无符号不允许存储负值,这大致可以使正数的上限提高一倍。
有符号和无符号使用相同的存储空间,具有相同的性能。
1.2、什么是上溢出、下溢出?
假设trade表有如下字段:
`status` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '状态',
update trade set status = 256 where id = 1001;
update trade set status = -1 where id = 1001;取决于不同的MySQL版本和配置,上面两条 sql 在强校验模式下会直接报错;
在弱校验下会更新成功,最终的值分别被更新为255、0。
1.3、tinyint(1)和tinyint(3)有什么区别?
对大多数应用来说没有意义,他不会限制值的合法范围,只是规定了MySQL的一些交互工具来显示的字符个数,对于存储和计算来说,他们都是相同的。
1.4、其余数值类型
decimal
float
double但是应用常见不多,比如需要存储余额、价格等浮点类型,大部分情况下也可以 * 100 转为int或bigint。
2、字符
2.1、常见的字符类型
char 一般适用于手机号、身份证号 varchar
utf-8下: 一个汉字 = 3个字节 一个英文字符 = 1个字节
gbk下: 一个汉字 = 2个字节 一个英文字符 = 1个字节
varchar是变长的,内部需额外使用1或2个字节用来字符串的长度(<=255使用1个,否则使用2个)
5.0版本之后,varchar(50),50指的是50个字符(4.0的时候是字节),分别可以存储50个汉字、或50个数字、或50个字母;char(50) 同理。
同样的问题,varchar是否会出现溢出问题呢?
`trade_id` varchar(20) NOT NULL DEFAULT '' COMMENT '订单号',
insert into trade set trade_id = '123456789012345678901';
ERROR 1406 (22001): Data too long for column 'trade_id' at row 1;取决于版本和MySQL的配置,在强校验情况下,sql会直接报错;
在弱校验情况下,SQL执行成功,多余的部分被截取掉,SQL产生一个warning;
2.2、其余字符类型
binary 二进制字符串,存储的是字节码而不是字符
varbinary
blob
text
enum
set3、日期、时间
datetime 从1001年到9999年,精度秒,格式 "2019-01-25 22:00:00"
timestamp 从1970年到2038年,精度秒,格式 "2019-01-25 22:00:00"除了特殊情况下,尽量使用timestamp,因为它比datetime的空间效率高。
用整数存储时间戳是否会更好呢?这不会带来任何收益,具体业务具体分析。
4、你不知道的null
我们可能都听说过:尽量避免使用null,建表的时候也尽量带上not null,why?
因为null的使索引、统计、存储 都变的更加复杂,对SQL优化极其不友好。
假设某表有如下字段:
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`year` int(10) default null,
该表 insert 10条数据,其中9条数据的year字段值为null,一条值为2019,然后分别执行如下sql
select count(1) from test where year = null;
select count(1) from test where year != null;
select count(1) from test where year != 2018;
update trade set year = year+1 where id = 1;可以发现,如果未了解过的话,还是很容易出现判断错误的情况。
5、为什么一定要有主键
给一张表设置主键,除了自增确保数据唯一,还有什么作用呢?
这个在另一篇博客有讲到MySQL的聚集索引,可以参考:juejin.cn/post/684490…
还有另外的原因:
对于无主键的表,如果在未命中索引的情况下、且为row模式的主从架构中进行delete操作,会导致备库夯住。因为MySQL的锁是加在索引上的,表中没有主键,在row模式下,每删一条数据都会做全表扫,也就是说一条delete,如果删了10条,会做10次全表扫。所以slave一直卡住;
更新聚集索引的代价极高,因为要强制InnoDB将每个被更新的行移动到新的位置;
Innodb中的每张表都要有一个聚集索引,因为聚集索引是以物理磁盘顺序来存储的,自增主键会把数据自动向后插入,避免了插入过程中的聚集索引排序问题,因为聚集索引的排序,必然会带来大范围的数据的物理移动,这里面带来的磁盘IO性能损耗是非常大的,而且还可能触发物理磁盘上的移动,于是就可能出现page分裂,表碎片横生。