数据库性能优化策略

有数据代表:用户能够承受的最大等待时间为8秒。 
以前曾见过某个产品的一个列表页,40秒左右才能加载出来,几乎没有进行任何优化措施。 
没有索引,没有缓存机制,没有进行sql优化(sql语句很长,而且各类left join表关联)。 
数据库优化策略有不少,设计初期,创建好的数据结构对于后期性能优化相当重要。由于数据库结构是系统的基石,基础打很差,使用各类优化策略,也不能达到很完美的效果。mysql

一:规范化与反规范化

你们都据说过:数据库设计三大范式. 
1.第一范式(确保每列保持原子性) 
第一范式是最基本的范式。若是数据库表中的全部字段值都是不可分解的原子值,就说明该数据库表知足了第一范式。sql

2.第二范式(确保表中的每列都和主键相关) 
第二范式在第一范式的基础之上更进一层。第二范式须要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不能够把多种数据保存在同一张数据库表中。数据库

3.第三范式(确保每列都和主键列直接相关,而不是间接相关) 
第三范式须要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。缓存

没有最好的设计,只有最合适的设计,因此不要过度注重理论。三范式能够做为一个基本依据,不要生搬硬套。 
数据库操做中最为耗时的操做就是 IO 处理,大部分数据库操做 90% 以上的时间都花在了 IO 读写上面。因此尽量减小 IO 读写量,能够在很大程度上提升数据库操做的性能。性能优化

二:优化策略:

在设计表时应同时考虑对某些表进行反规范化,方法有如下几种:数据结构

一是分割表。 
分割表可分为水平分割表和垂直分割表两种: 
水平分割是按照行将一个表分割为多个表,这能够提升每一个表的查询速度,但查询、更新时要选择不一样的表,统计时要汇总多个表,所以应用程序会更复杂。 
垂直分割是对于一个列不少的表,若某些列的访问频率远远高于其它列,就能够将主键和这些列做为一个表,将主键和其它列做为另一个表。经过减小列的宽度,增长了每一个数据页的行数,一次I/O就能够扫描更多的行,从而提升了访问每个表的速度。可是因为形成了多表链接,因此应该在同时查询或更新不一样分割表中的列的状况比较少的状况下使用。数据库设计

二是保留冗余列。当两个或多个表在查询中常常须要链接时,能够在其中一个表上增长若干冗余的列,以免表之间的链接过于频繁,通常在冗余列的数据不常常变更的状况下使用。性能

三是增长派生列。派生列是由表中的其它多个列的计算所得,增长派生列能够减小统计运算,在数据汇总时能够大大缩短运算时间。优化

在数据库的设计中,数据应当按两种类别进行组织:频繁访问的数据和频繁修改的数据。 
对于频繁访问可是不频繁修改的数据,内部设计应当物理不规范化。 
对于频繁修改但并不频繁访问的数据,内部设计应当物理规范化。 
有时还需将规范化的表做为逻辑数据库设计的基础,而后再根据整个应用系统的须要,物理地非规范化数据。 
规范与反规范都是创建在实际的操做基础之上的约束,脱离了实际二者都没有意义。只有把二者合理地结合在一块儿,才能相互补充,发挥各自的优势。spa

适当拆分 
有些时候,咱们可能会但愿将一个完整的对象对应于一张数据库表,这对于应用程序开发来讲是颇有好的,可是有些时候可能会在性能上带来较大的问题。

当咱们的表中存在相似于 TEXT 或者是很大的 VARCHAR类型的大字段的时候,若是咱们大部分访问这张表的时候都不须要这个字段,咱们就该义无反顾的将其拆分到另外的独立表中,以减小经常使用数据所占用的存储空间。这样作的一个明显好处就是每一个数据块中能够存储的数据条数能够大大增长,既减小物理 IO 次数,也能大大提升内存中的缓存命中率。

适度冗余 
为何咱们要冗余?这不是增长了每条数据的大小,减小了每一个数据块可存放记录条数吗? 
确实,这样作是会增大每条记录的大小,下降每条记录中可存放数据的条数,可是在有些场景下咱们仍然仍是不得不这样作: 
1.被频繁引用且只能经过 Join 2张(或者更多)大表的方式才能获得的独立小字段。 
2.这样的场景因为每次Join仅仅只是为了取得某个小字段的值,Join到的记录又大,会形成大量没必要要的 IO,彻底能够经过空间换取时间的方式来优化。不过,冗余的同时须要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新。

三:其余技巧:

1:字段类型优化 
下面的这些关于字段类型的优化建议主要适用于记录条数较多,数据量较大的场景,由于精细化的数据类型设置可能带来维护成本的提升,过分优化也可能会带来其余的问题:

(1)数字类型 
非万不得已不要使用DOUBLE,不只仅只是存储长度的问题,同时还会存在精确性的问题。一样,固定精度的小数,也不建议使用DECIMAL。 
非万不得已不要使用DOUBLE,不只仅只是存储长度的问题,同时还会存在精确性的问题。一样,固定精度的小数,也不建议使用DECIMAL 
(2)字符类型 
非万不得已不要使用 TEXT 数据类型,其处理方式决定了他的性能要低于char或者是varchar类型的处理。定长字段,建议使用 CHAR 类型,不定长字段尽可能使用 VARCHAR,且仅仅设定适当的最大长度,而不是很是随意的给一个很大的最大长度限定,由于不一样的长度范围,MySQL也会有不同的存储处理。

(3)时间类型 
尽可能使用TIMESTAMP类型,由于其存储空间只须要 DATETIME 类型的一半。对于只须要精确到某一天的数据类型,建议使用DATE类型,由于他的存储空间只须要3个字节,比TIMESTAMP还少。不建议经过INT类型类存储一个unix timestamp 的值,由于这太不直观,会给维护带来没必要要的麻烦,同时还不会带来任何好处。

2:合理使用索引

3:缓存机制

4:用EXPLAIN使你的SELECT查询更加清晰

5:利用LIMIT 1取得惟一行

6: 尽可能避免SELECT *命令

7:使用ENUM而不是VARCHAR

8:尽量的使用NOT NULL 
 NULL 类型比较特殊,SQL 难优化。虽然 mysql NULL类型和 Oracle 的NULL 有差别,会进入索引中,但若是是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。此外,NULL 在索引中的处理也是特殊的,也会占用额外的存放空间。

 不少人以为 NULL 会节省一些空间,因此尽可能让NULL来达到节省IO的目的,可是大部分时候这会拔苗助长,虽然空间上可能确实有必定节省,却是带来了不少其余的优化问题,不但没有将IO量省下来,反而加大了SQL的IO量。因此尽可能确保 DEFAULT 值不是 NULL,也是一个很好的表结构设计优化习惯。

参考:

http://blog.csdn.net/u013628152/article/details/51835121

相关文章
相关标签/搜索