MySQL优化(一)—— 表的优化

MySQL 阅读: 135

定长与变长分离

所谓定长与变长分离是指:将表中固定长度的字段和可变长度的字段分开,将他们放在不同的表中。

固定长度类型:整型、浮点型、时间和日期型、enum、set、文本中char型
可变长度类型:除char外的文本型、blob

为什么要这么做呢?如果一个表中的字段都是固定长度的字段,那么每行记录的长度都是固定的(fixed),这样如果想找到第N行的数据位置,直接使用N*RowSize即可,访问速度很快。

所以建议将核心字段设置为固定长度, 而变长字段,适合单放一张表, 使用主键与核心表关联起来。

常用和不常用分离

所谓常用和不常用分离是指:将表中常用的字段和不常用的字段分开,将他们放在不同的表中。

分离出不常用字段能够增加数据取出效率。比如在博客程序中,对于文章表可以将文章内容字段和其他不常用的字段分离出来,放在另一个表中。因为对于博客,文章列表中的文章数量更多,而且在列表不需要使用文章内容(就算使用也不需要使用全部内容)等比较详细的内容,单独存放它们可以增加查询效率。

这个优化需要结合具体的业务,分析字段的查询场景或者进行统计,将查询频度低的字段拆出来。

1对多中,对需要关联统计得出的信息,添加冗余字段

这个优化可以拿博客程序来说明:博客中一般都有多个文章分类(或者叫栏目),如何统计每个分类下的文章数量呢?可以这样写SQL语句:

select category.id, category.name, count(article.id) as count
from category
inner join article on category.id = article.cat_id
group by article.cat_id

这个统计功能的SQL用到了两张表的连接。其实可以在文章分类表中直接加一个文章数量字段对改分类的文章进行计数。只需要每次增删文章的时候去更新这个字段就可以了,这样做之后只需要查询文章分类就可以实现统计功能,相比于原来的SQL语句,可以节省一定的时间。

这是一种在计算机学科中经常使用的“空间换时间”的思想。

列类型选择原则

字段类型优先级:

整型,浮点型 > date,time > enum,char > varchar > blob,text

各种字段类型的特点:

  • 整型,浮点型: 定长存储,没有国家/地区之分,也没有字符集的差异,因此处理速度快。比如tinyint 1,2,3,4,5与char(1) a,b,c,d,e相比较:从空间上,都是占1个字节,但是使用 order by 排序时,前者快。原因: 后者需要考虑字符集与校对集(就是排序规则)。
  • date,time:定长存储,运算快,节省空间。 但需要考虑时区,写sql时也不方便,如 where > '2005-10-12'
  • enum: 定长, 内部用tinyint存储,但使用字符串查询时,内部要经历字符串与整数值的转化。
  • char: 定长, 但需要考虑字符集和(排序)校对集。
  • varchar:不定长,并且要考虑字符集的转换与排序时的校对集,速度慢。
  • text,Blob:无法使用内存临时表(排序等操作只能在磁盘上进行),速度较慢。

PS: 关于date/time的选择,大师的明确意见是直接选用 int unsgined not null,只存储时间戳即可。详见:http://www.xaprb.com/blog/2014/01/30/timestamps-in-mysql/

还有常见的存储性别, 以utf8为例,可以选择的类型有:

  1. char(1): '男','女',3个字长字节
  2. enum(‘男’,’女’): 定长1个字节,内部转成tinyint来存,多了一个转换过程
  3. tinyint:定义0表示无,1表示男,2表示女,定长1个字节

根据上面字段类型优先级,选择tinyint最好。

字段长度够用就行

定义字段长度时候,不要过长,因为较大的字段不仅浪费内存,而且也会影响查询速度。

以年龄为例, tinyint unsigned not null,可以存储0-255岁,对于人来说已经足够了,而用int范围过大,浪费了3个字节。

如果varchar(10) ,varchar(300)存储的内容相同, 但在表联查时,varchar(300)要花更多的内存。

尽量避免用NULL

我们经常能看到这条,但为什么呢?

  1. NULL不利于索引,要用特殊的字节来标注。NULL在磁盘上占据的空间其实更大。(MySQL 5.7已对NULL存储做了改进,但查询仍是不便)
  2. 查询也不方便。判断时NULL时,不能直接用=NULL和!=NULL,需要使用IS NULL和IS NOT NULL。

所以定义字段时尽量使用NOT NULL而不是NULL。

版权声明:本文为博主原创文章,转载需注明来自: 洛洛の空间