favouriter 2020-06-05
MySQL表设计有一些比较重要的点,面试的时候常常会被问到。
为什么一定要设置一个主键?
在不设置主键的情况下,InnoDB存储引擎会帮你生成一个隐藏列作为自增主键。因此,手动指定主键可以为以后的维护带来便利,比如说在自定义主键上建立主键索引来提高查询效率。
主键是用自增还是随机(UUID)?
主键建议是自增的好。因为InnoDB中的主键是聚簇索引,如果主键是自增的话,每次插入新的记录就会顺序添加到当前索引节点的后续位置,当一页写满就会自动开辟新的页。如果不是自增主键,可能就会在中间插入,引发页的分裂导致产生很多表空间的碎片。
可以理解为当主键是UUID的时候,插入表记录的时间会更长,占用空间也会更大。
主键为什么不推荐有业务含义?
主要有两点。
1.任何有业务含义的列都有改变的可能性,主键一旦带上了业务含义,那么主键就有可能发生变更。而主键一旦发生变更,该记录数据在磁盘上的存储位置就会发生改变,甚至有可能会引发页分裂导致产生空间碎片。
2.带有业务含义的主键就不一定是顺序自增的了,这样就会导致数据的插入顺序不到有序的,也不能保证后面插入数据的主键一定比前面的数据大。如果出现了后面插入数据的主键比前面的小的情况,就有可能引发页分裂导致产生空间碎片。
表示枚举的字段为什么不用enum类型?
表示枚举的字段一般选用tinyint类型。不选用enum类型主要有两个原因:
1.enum类型的order by的操作效率低,需要额外的操作。
2.如果枚举值是数值类型的,会很容易出现语法陷阱,枚举的下标和数值很容易会被弄混淆。
货币字段用什么类型?
如果货币单位是分,可以是int类型;如果坚持用元,则要用decimal类型。
但是是不能用float和double类型的,因为这两个类型是以二进制存储的,会有一定的误差。比如float类型如果你insert一个1234567.23,查询出来的结果可能是1234567.25。
时间字段用什么类型?
时间字段的话需要结合项目背景,varchar、timestamp、datetime或bigint类型都可以。
1.varchar类型。如果用varchar类型来存时间,优点在于显示直观,存取都方便。但是缺点也是挺多的,比如插入的数据没有校验,某一天你可能会发现数据库中存了一个2019-06-31的数据。其次,做时间比较运算时需要用str_to_date()
等函数将其转化为时间类型,除非建立基于函数的索引,否则这么写是无法命中索引的,数据量一大,查询效率就会很低。
2.timestamp类型。这个类型是四个字节的整数,它能表示的时间范围为1970-01-01 08:00:01到2038-01-19 11:14:07,而2038年以后的时间,是无法用timestamp类型存储的。但是它有一个优势是它带有时区信息的,一旦系统中的时区发生改变,项目中的该字段的值也会自己发生改变。
3.datetime类型。datetime类型的储存占用8个字节,存储的时间范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。显然,存储时间范围更大,但是它存储的是时间绝对值,不带有时区信息。如果改变了数据库的时区,该项的值不会自己发生变更。
4.bigint类型。这个类型也是8个字节,自己维护一个时间戳,表示范围比timestamp类型大多了。缺点就是要自己维护,不大方便。
为什么不直接存储图片、音频和视频等大容量内容?
在实际应用中,一般都是用HDFS来存储文件的,在MySQL中只会存文件的存放路径。但是实际上MySQL是有提供两个字段类型被涉及用来存放大容量文件的,一个是text类型,一个是blob类型。然而在生产中基本不会使用这两个类型,主要原因如下:
1.MySQL内存临时表不支持text和blob这样的大数据类型。如果查询中包含这样的数据,那么在排序等操作的时候就不能够使用内存临时表,只能使用磁盘临时表,会导致查询效率低下。
2.这两种类型会造成binlog的内容太多。因为数据的内容比较大,也就会造成binlog的内容比较多。我们知道,主从同步是通过binlog来进行的,如果binlog过大,就会导致主从同步的效率问题。
为什么字段要被定义为NOT NULL?
1.索引的性能不好。MySQL难以优化引用可空列查询,它会使得索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要MySQL内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节。
2.查询可能会出现一些不可预料的结果。比如说使用count()聚合函数去统计一个可为空的字段,那么最后统计出来的记录数可能会和实际的记录数不同。
MySQL表设计面试题的总结
MySQL如果要深入提问的话,可以把你问到叫爸爸,因此平时要注意多积累。
另外要注意的是,上面的回答都是基于InnoDB存储引擎的。
"心结如果真的打不开,你就给它系成个花样儿,其实生活就需要这样。"