博客原文连接:https://www.cnblogs.com/studynote/p/8079154.htmlhtml
你们都据说过:数据库设计有几种范式,其中最主要知足第三范式.
1.第一范式(1NF):属性不可分
第一范式是最基本的范式。若是数据库表中的全部字段值都是不可分解的原子值,就说明该数据库表知足了第一范式。数据库
2.第二范式(2NF):知足1NF,彻底函数依赖
第二范式须要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不能够把多种数据保存在同一张数据库表中。缓存
3.第三范式(3NF):知足2NF,消除传递依赖
第三范式须要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。数据库设计
4.BC范式(BCNF):符合3NF,而且,主属性不依赖于主属性。
若一个关系达到了第三范式,而且它只有一个候选码,或者它的每一个候选码都是单属性,则该关系天然达到BC范式。函数
5.第四范式(4NF):符合BCNF,要求把同一表内的多对多关系删除。性能
6.第五范式(5NF):符合4NF,将一个table尽量的分割成小的块,以排除在table中全部冗余的数据。fetch
没有最好的设计,只有最合适的设计,因此不要过度注重理论。
在数据库的设计中,数据应当按两种类别进行组织:频繁访问的数据和频繁修改的数据。
对于频繁访问可是不频繁修改的数据,数据表设计应该反规范化。
对于频繁修改但并不频繁访问的数据,数据表设计应当规范化。
有时还需将规范化的表做为逻辑数据库设计的基础,而后再根据整个应用系统的须要,进行反规范化。
规范与反规范都是创建在实际的操做基础之上的约束,脱离了实际二者都没有意义。只有把二者合理地结合在一块儿,才能相互补充,发挥各自的优势。优化
在设计表时应同时考虑对某些表进行反规范化,方法有如下几种:设计
一是分割表。
分割表可分为水平分割表和垂直分割表两种:
水平分割是按照行将一个表分割为多个表,这能够提升每一个表的查询速度,但查询、更新时要选择不一样的表,统计时要汇总多个表,所以应用程序会更复杂。
垂直分割是对于一个列不少的表,若某些列的访问频率远远高于其它列,就能够将主键和这些列做为一个表,将主键和其它列做为另一个表。经过减小列的宽度,增长了每一个数据页的行数,一次I/O就能够扫描更多的行,从而提升了访问每个表的速度。可是因为形成了多表链接,因此应该在同时查询或更新不一样分割表中的列的状况比较少的状况下使用。htm
二是保留冗余列。当两个或多个表在查询中常常须要链接时,能够在其中一个表上增长若干冗余的列,以免表之间的链接过于频繁,通常在冗余列的数据不常常变更的状况下使用。
三是增长派生列。派生列是由表中的其它多个列的计算所得,增长派生列能够减小统计运算,在数据汇总时能够大大缩短运算时间。
优化原则:
1.尽可能使用定长类型,由于固定长度的表会更快。
若是表中的全部字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length”。 例如,表中没有以下类型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一个这些字段,那么这个表就不是“固定长度静态表”了,这样,MySQL 引擎会用另外一种方法来处理。
固定长度的表会提升性能,由于MySQL搜寻得会更快一些,由于这些固定的长度是很容易计算下一个数据的偏移量的,因此读取的天然也会很快。而若是字段不是定长的,那么,每一次要找下一条的话,须要程序找到主键。
而且,固定长度的表也更容易被缓存和重建。不过,惟一的反作用是,固定长度的字段会浪费一些空间,由于定长的字段不管你用不用,他都是要分配那么多的空间。
使用“垂直分割”技术,你能够分割你的表成为两个一个是定长的,一个则是不定长的。
2.尽可能使用较小的类型,由于更节省存储空间,且越小的列会越快。
例如:
a.尽量用MEDIUMINT, SMALLINT 或是更小的 TINYINT代替INT;
b.对于只须要精确到某一天的数据类型,用DATE代替DATETIME好得多
c.使用TIMESTAMP类型代替DATETIME类型,由于其存储空间只须要DATETIME类型的一半
d.把IP地址存成 UNSIGNED INT
e.使用ENUM而不是VARCHAR。ENUM 类型是很是快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来作一些选项列表变得至关的完美。
1.永远为每张表设置一个ID
咱们应该为数据库里的每张表都设置一个ID作为其主键,并且最好是一个INT型的(推荐使用UNSIGNED),并设置上自动增长的AUTO_INCREMENT标志。
2.合理使用索引
对查询进行优化,要尽可能避免全表扫描,首先应考虑在 where 及 order by 涉及的列上创建索引。索引并非越多越好,索引当然能够提升相应的 select 的效率,但同时也下降了 insert 及 update 的效率,由于 insert 或 update 时有可能会重建索引,因此怎样建索引须要慎重考虑,视具体状况而定。
3.尽量的使用NOT NULL
NULL 类型比较特殊,SQL 难优化,如难以创建索引。并且NULL值存储时可能还比EMPTY须要更多的存储空间。
1.尽可能避免SELECT *命令,只返回须要的字段
2.利用LIMIT 1取得惟一行
当你查询表的有些时候,你已经知道结果只会有一条结果,但由于你可能须要去fetch游标,或是你也许会去检查返回的记录数。
在这种状况下,加上 LIMIT 1 能够增长性能。这样同样,MySQL数据库引擎会在找到一条数据后中止搜索,而不是继续日后查少下一条符合记录的数据。
3.应尽可能避免在 where 子句中对字段进行 null 值判断,不然将致使引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
4.应尽可能避免在 where 子句中使用 != 或 <> 操做符和not in,不然将致使全表扫描。
5.若是 where 子句的字段中存在某个字段没有索引,将致使引擎放弃使用索引而进行全表扫描。
6.搜索字串column LIKE '%a'没法利用索引的检索优点,column LIKE 'a%'才能利用索引的检索优点。
7.应尽可能避免在 where 子句中对字段进行表达式操做,这将致使引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2 = 100
应改成:
select id from t where num = 100*2
8.应尽可能避免在where子句中对字段进行函数操做,这将致使引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3) = ’abc’ -–name以abc开头的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0 -–‘2005-11-30’ --生成的id
应改成:
select id from t where name like 'abc%'
select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'
9.不要在 where 子句中的“=”左边进行函数、算术运算或其余表达式运算,不然系统将可能没法正确使用索引。
10.避免对实数和date/time等类型使用=操做符,由于可能得不到实际的结果。
11.避免使用or如:
select id from t where num=10 or Name = 'admin'
能够这样查询:
select id from t where num = 10
union all
select id from t where Name = 'admin'