【Database】性能调优学习笔记(1)- 优化表设计
一般来说,优化表设计有一些原则:
- 设计表结构尽量满足三范式
- 有时有可能追求效率可以进行适当冗余字段,进行反范式设计
- 表字段的数据类型选择,同样关系到了查询效率的高低和存储空间的大小
一般情况下,使用设计出符合数据库范式的表结构,有利于保证数据的正确性和严谨性,但有些时候为了效率可能会进行反范式设计,下面会有相关的记录。
常用的数据库范式有3种,分别是:1NF(第一范式) | 2NF(第二范式) | 3NF(第三范式)。
一般来说满足3NF,那么必定满足2NF,以此类推。
个人觉得一般的解释都比较抽象,下面会配合着相关的例子、解释,结合自身的理解来进行记录。
在此之前对一些名词做出一些解释:
比如现在有张表1Student,字段为:Number、IdNumber、Name、Age、ClassId;表2Class,字段为:ClassId、ClassName
超键:能唯一标识元组的属性集叫做超键。
例:R1(Number、IdNumber)或者R2(Number、Age)就是超键候选键:如果超键不包括多余的属性,那么这个超键就是候选键。
例:个人认为能利用来标识这条数据是唯一的字段,如上述的Number或者IdNumber主键:用户可以从候选键中选择一个作为主键。
外键:如果数据表 R1 中的某属性集不是 R1 的主键,而是另一个数据表 R2 的主键,那么这个属性集就是数据表 R1 的外键。
例:ClassId在Student表中不是主键,但在Class表中是主键,那么ClassId就是Student表中的外键,当然这是要设置的。主属性:包含在任一候选键中的属性称为主属性。
非主属性:与主属性相对,指的是不包含在任何一个候选键中的属性。
(1)、1NF 指的是数据库表中的任何属性都是原子性的,不可再分。
例如:Student作为一个字段,有点歧义,因为Student是一个对象,它有可能有Name、Age。
那么它就可以拆分、不唯一,因此违反了1NF。
(2)、2NF 指的数据表里的非主属性都要和这个数据表的候选键有完全依赖关系。
这里说得比较抽象,举个例子解析一下,比如:新建一张表,字段有:StudentNum、StudentName、StudentAge、LessonNum、LessonName、LessonAddress。
这张表就不符合2NF了,按上述的解释就是
StudentNum决定了StudentName和StudentAge。
LessonNum决定了LessonName、LessonAddress。
换言之LessonName、LessonAddress并非完全依赖StudentNum。
其实感觉有点复杂,个人认为简单点的描述就是,这个表缺一个ID主键,让所有字段都来依赖它,用来标识这是一条唯一的数据。但加了ID以后,虽然符合了条件,但同时会出现一些比如数据冗余、CUD异常的情况,数据的正确性将受到损害。
(3)、3NF 在满足 2NF 的同时,对任何非主属性都不传递依赖于候选键
个人认为这里的大概意思就是是在基于满足2NF的前提下,把不同的对象拆成单独的表,后用外键、以及中间表关联起来就可以,而实际生产中也是需要这么做的,否则数据会略显混乱。
在日常生产中,满足3NF的设计,在进行查询的难免需要进行表与表之间的连接以获取完整的数据。但随着时间的推移,数据量逐渐增大,此时通过连接查询的效率会非常的低。所以这时候需要一定的反范式设计来提高查询的效率。
例如前面说到的表Student与Class,可以适当的将ClassName冗余到Student表中,在Create或者Update的时候将ClassName的数据也写入Student表中,那么在查询学生相关信息的时候就可以仅仅进行单表查询,大大提高效率。
同时在另外的场景中也适用,比如交易信息,在订单完成的那一刻,所有的东西都是确定的了。但用户的信息有可能经过用户自己的更新、修改,不断的在变化,此时就不可以使用连接进行即时查询。所以同样需要进行部分字段的冗余,当然这是其中一种方法,本质上也可以将这些信息存到另外一张表中。
- 如果字段可以采用数值类型就不要采用字符类型
- 字符的长度根据实际的业务尽量设计得短一些
- 针对字符类型来说,如果字符的长度固定,就可以使用char类型;当长度不固定的时候通常采用Varchar类型
学习参考来自课程《SQL必知必会》