您的位置:首页 > 数据库 > MySQL

表设计优化(MySQL作为报表数据库)

2017-03-16 12:16 633 查看

表设计优化(MySQL作为报表数据库)

目前虽然有较多的大数据处理框架,但也有其局限性,其功能往往无法和传统DB媲美。使用传统DB,可以利用简单的SQL语句获得结果,利用包括索引和表关联等成熟技术获得报表,可大大提高效率。在此提出一些在表设计时可考虑的优化方法。

 

1、选择紧凑的数据类型。

例如对于日期时间,使用timestamp表示只需4个字节,可保存到2038年;使用Unix time(1970至今的秒数),并使用4字节unsignedint,可保存到2106年;如果只需要日期,使用date类型只需3字节;如果只需要时间,可以使用time类型或使用较少字节的整数存储秒数即可。

 

2、优化枚举的使用。

在实际开发中,数据库的枚举类型有可能使用不多,在遇到枚举的时候,我见过许多程序员都是使用int类型存储,但这其实很浪费。

在MySQL中,根据枚举个数的不同,一个枚举可能占用一个或两个字节,实践中可用byte或smallint来表示枚举类型。即使有些枚举编码大于127,可使用unsigned byte;如果枚举编码有大于255的情况,可使用代码转义或MySQL的enum等方式;只要枚举个数小255,可用一个字节存储。

有些字段并不是枚举类型的,但实际上可看做枚举。例如,在程序中用到省份但不需要用到市、区等,则省份的id如果使用int存储就浪费了,总之如果总个数在255以内使用一个byte存储即可;如果在65535个以内使用smallint存储即可。

 

3、选择二进制类型可节省CPU。

如果使用char或者varchar存储字符,且表的字符集为utf8等变长字符集,则排序、比较时都比较耗CPU,因为需要根据字符集来判断先后顺序。使用binary(字节数)、varbinary(字节数)代替后,比较排序时无需根据字符集判断,直接按字节比较大小即可,适用于没有中文只有ascii字符的情况。

使用binary可指定字节数,能更方便开发人员对其进行控制,需要多少个字节就指定多少个字节,以满足需求为准,不用拘泥于数据库的类型。

另外,某些字段能用数值类型也可以用字符串类型,则能使用数值表示的字段,尽量不用字符串,因为数值的效率通常更高。

 

4、多个枚举列的组合优化为查找表。

很多表中都存在许多可使用枚举值来表示的列,这些列的枚举值往往就一两个或三四个,但却要单独占用一列,如果这样的列比较多,则占用的空间、查询表时的花销等都相当可观。因此,将多个枚举列的组合抽取出来,作为查找表,可以很大程度上减小数据表的字段数及所需的磁盘空间,并优化查询速度等。

例如,某电商订单表中有仓库id(全国假设有10个仓库)、配送方式(5种配送)、来源平台(PC、手机两种)、库存类型(实物、预售两种)、商家类型(自营、海外购等)、生产类型(网仓直发、本地仓直发、移仓等)。这些列可能用于查询条件,在表中通常会记录为int类型,经过实际测试,这些列组合数在500种以内。因此,可设置查找表,这些枚举的不同组合都在查找表中放一条记录,查找表主键使用2字节的smallint即可,在订单表中无需记录如此多的字段,只需记录查找表主键,占用2字节即可。

如果按通常的设计需要在订单表存储6个int即24个字节。此举将记录大小从24字节缩小到2字节,且并不会影响性能,因为查找表非常小。有许多的枚举时,将枚举分为多组,各组使用不同的查找表,能大大提高性能。

 

5、分离出非查询条件的字段。

有一些字段在查询条件中不会用到,只会在结果中用到(例如客户名称、快递公司名称)。对于这种情况,可将这些字段分离到单独的表中,实际上形成维表。分离出一些字段后,原表变得更小,查询效率大大提高;如果需要展现这些字段时,可再单独根据主键等查询分离出来的表。

 

6、去掉不必要字段(可事后推导)

例如,订单表中有五级收货地址,包括国家、省、市、区县、街道,分别为5个int,如果只是国内订单,没有必要记录国家和省;如果查询条件无需使用到市和区县,可只记录街道即可,需要展示的时候可同街道的id得出上级地址的id。

 

7、合理的主键、索引,字段尽量NOTNULL。

在InnoDB中,主键会自动出现在所有的非主键索引中,因此主键不能占用过多空间。

主键自增可提高插入性能,如果有非自增的唯一索引,也可以使用查找表的方式将其改为自增后作为主键。

如果使用UUID类型的主键,可在前面加上例如时间之类的值,确保主键基本是递增的。

如果使用复合主键,区分度高的列通常应在前面。

索引不应过多,因为一个查询通常只使用一个索引(最新版的MySQL也可能会使用多个索引后将结果做交集或并集)。

字段要尽量设置为不允许null。有部分人认为,MySQL设计表时应尽量少约束,将约束在应用代码中实现。但如果一味教条地遵守此规则,就会显得不实际而走极端。有一些约束还是在数据库里做效率最好。另外,字段设置not null后,在MySQL使用索引、生成查询计划的时候都是有利的。

 

8、应对需要多表多字段关联join的情况。

如果两个大表经常join,join条件比较多且使用等于表达式,则可以将这多个字段哈希后作为单独的列,join的时候先比较哈希列,相等后再比较实际的join列,这样可以减轻join时的计算量。如果哈希结果为整数,则比较效率会更好。

将可能用到的字段冗余到一张表中,避免大表join。例如,在报表项目中,可能会在事实表存储一些冗余字段,而不是完全遵循第三范式,从而形成字段较多的所谓宽表。

查询的时候可以选择数据量较小或过滤后数据量较小的驱动表。在from子句中使用join时MySQL会先判断是否能用到索引,如果能用到索引则可能会自动选择驱动表,但改成straight_join后则按from子句中的先后顺序,选择第一个表为驱动表,在写代码的人比较确定的时候可使用这种方式。

 

9、设置合理的row_format。

如果磁盘较慢,则可使用压缩格式(创建表的时候指明row_format=compressed);如果CPU是瓶颈,则应该使用fixed行格式,行的长度是固定的,各列在行中位置也是固定的,减少计算量;如果二者比较均衡,则保持默认的行格式compact即可。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息