MySQL性能优化(二):优化数据库的设计

一:数据库的设计

数据库的创建没有什么要说的,这里只想说一点关于数据库名的命名一般和项目的名称保持一致,不要随意的起名字。

二:表的设计

数据库表的好坏是数据库设计的基础,而且一旦数据库表设计完毕并投入使用,将来再进行修改就比较麻烦,因此在进行数据库设计的时候一定要尽可能的考虑周到。

1. 表名

  • 表的命名一般遵守 “业务名称 _ 表名“或者是“项目名_ 表名“的格式,对于业务名称一般都是简写,不全拼,全拼表名会太长,如sys_user(系统模块对应的用户表),对于一些公用的可以使用tbl(table)作为模块名,如字典表 tbl_dictionary

  • 表名不使用复数形式,表名应该仅仅表示表里面的实体内容,不应该表示实体数量

为什么要使用前缀?

  • 如果多个项目都使用同一个数据库的话,可以防止命名冲突,例如用户表,如果没有前缀,只能有一个叫user的,其它项目也想使用这个名字就没法用了,为了格式统一大家都加个项目名称前缀这样就可以了,如xxx_user, yyy_user; 在公司中可以经常看到有时候数据库中的所有表都用项目的简称做前缀,一般只有这一种前缀。 不同项目一般都会创建自己的数据库,但是不能保证万一会使用同一个数据库的情况,如两个项目关联很大可能会使用同一个数据库。
  • 在比较复杂的系统中,通过表名前缀可以大概了解到表所在的模块和分类,这样做日常开发和运维的时候看起来比较方便,新人了解系统数据结构的时候也有章可循。

2. 字段名

  • MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、 表名、字段名,都不允许出现任何大写字母,避免节外生枝。
  • 一般所有表都要有id, id必为主键,类型为bigint unsigned,单表时自增、步长为1; 有些特殊场景下(如在高并发的情况下该字段的自增可能对效率有比价大的影响)id是通过程序计算出来的一个唯一值而不是通过数据库自增长来实现的。
  • 一般情况下主键id和业务没关系的,例如订单号不是主键id,一般是订单表中的其他字段,一般订单号为字符类型
  • 一般情况下每张表都有着四个字段create_id,create_time,update_id,update_time 其中create_id表示创建者id,create_time表示创建时间,update_id表示更新者id,update_time表示更是时间,为了能够追踪数据的来源和修改
  • 最好不要使用备用字段(个人观点), 禁用保留字,如 desc、range、match、delayed 等
  • 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否), 任何字段如果为非负数,必须是unsigned。表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除
  • 如果某个值能通过其他字段能计算出来就不需要用个字段来存储,减少存储的数据
  • 为了提高查询效率,可以适当的数据冗余,注意是适当
  • 尽量不使用外键, 数据的完整性靠程序来保证
  • 单条记录大小禁止超过8k, 一方面字段不要太多,有的都能上百,甚至几百个,另一方面字段的内容不易过大

3. 字段的数据类型

不同的数据类型搜索的方式不同,所以说要选择合适的数据类型。

用尽量少的存储空间来存数一个字段的数据, 缩小存储空间换取查询时间,能用int的就不用char或者varchar,能用tinyint的就不用int,使用UNSIGNED存储非负数值, 合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。 如果是正数,需要使用unsigned,其中无符号值可以避免误存负数,且扩大了表示范围。

字符类型

  • char是固定长度的字符类型,它的处理速度比varchar快,缺点是浪费存储空间,当实际存储的值小于指定的长度时会以空格来填充,对于长度变化不大并且对查询速度有较高的要求可以选择char。适合存储用户密码的MD5哈希值,它的长度总是一样的。对于经常改变的值,char也好于varchar,因为固定长度的行不容易产生碎片,对于很短的列,char的效率也高于varchar。char(1)字符串对于单字节字符集只会占用一个字节,但是varchar(1)则会占用2个字节,因为1个字节用来存储长度信息 。如果存储的字符串长度几乎相等,使用char定长字符串类型。
  • varchar是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长 度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
  • 不同存储引擎对char于varchar的使用原则不同,myisam:建议使用国定长度的数据列代替可变长度。innodb:建议使用varchar

数值类型

选用合适的长度非常重要,能用tinyint不用integer

  • 金额类型的字段尽量使用long用分表示,尽量不要使用bigdecimal,严谨使用float和double因为会丢失经度
  • 如果需要使用小数使用定点数decimal实际上是以字符串的形式存储的,所以更加精确,java中使用BigDecimal来处理
  • 不建议使用ENUM、SET类型,使用TINYINT来代替
数据类型 字节 长度
tinyint unsigned 1 字节 无符号:0~255
smallint unsigned 2 字节 无符号:0~65535
meidiumint unsigned 3 字节 无符号:0~2^24-1
int unsigned 4 字节 无符号:0~42.9亿
bigint unsigned 8 字节 无符号:0~10的19次方
再长用varchar

误区:
创建表时我们经常看到长度这一列,例如 tinyint(2),对于整型来说小括号中的2不是指的存储长度,而是指的零填充,对于字符串可能是指的是长度
zerofill : 零填充,当数据的长度小于指定的长度时,会使用0来填充缺失的长度。零填充在mysql客户度中看不出来,通过使用命令行可以看出来。
这里写图片描述

这里写图片描述
这里写图片描述

日期类型

根据实际需要选择能够满足应用的最小存储日期类型,如果应用只需要记录年份,那么仅用一个字节的year类型。

  • 如果记录年月日用Date
  • 如果记录年月日并且记录的年份比较久远选择datetime,而不要使用timestamp,因为timestamp表示的日期范围要比datetime短很多
  • 如果记录的日期需要让不同时区的用户使用,那么最好使用timestamp, 因为日期类型值只有它能够和实际时区相对应

PROCEDURE analyse(): 用于分析表的数据类型

SELECT * FROM tbl_user PROCEDURE analyse();

3. 是否为null

MySQL字段属性应该尽量设置为NOT NULL,除非你有一个很特别的原因去使用 NULL 值,你应该总是让你的字段保持 NOT NULL 。

在MySql中NULL其实是占用空间的,“可空列需要更多的存储空间”:需要一个额外字节作为判断是否为NULL的标志位“需要mysql内部进行特殊处理”, 而空值”“是不占用空间的。

含有空值的列很难进行查询优化,而且对表索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。

联表查询的时候,例如LEFT JOIN table2,若没有记录,则查找出的table2字段都是null。假如table2有些字段本身可以是null,那么除非把table2中not null的字段查出来,否则就难以区分到底是没有关联记录还是其他情况

在数据库里是严格区分的,任何数跟NULL进行运算都是NULL, 判断值是否等于NULL,不能简单用=,而要用IS NULL关键字。

使用 ISNULL()来判断是否为 NULL 值。 说明:NULL 与任何值的直接比较都为 NULL。

  • 1) NULL<>NULL的返回结果是NULL,而不是false。
  • 2) NULL=NULL的返回结果是NULL,而不是true。
  • 3) NULL<>1的返回结果是NULL,而不是true。

4. 存储引擎

常用的存储引擎的选择有MYISAM、InnoDB、MEMORY,不同的存储引擎支持的功能不一样。

  • MYISAM 不支持事务, 不支持外键,其优势是访问速度快,对事务完整性没有要求或者以select、insert为主的应用程序可以选择这个引擎,支持全文索引,表锁,注意:MYISAM 在删除数据时好像类似于逻辑删除,需要定时物理删除,清理碎片:optimize table 名称;
  • InnoDB 支持事务,不支持全文索引,标锁,支持外键
  • MEMORY:查询速度极快,数据在内存中不持久化,数据库重启数据就消失,类似于缓存的作用memcache

表引擎取决于实际应用场景;日志及报表类表建议用myisam,
与交易,审核,金额相关的表建议用innodb引擎。
如无说明,建表时一律采用innodb引擎

mysql5.0之后默认为InnoDB创建表的时候可以指定engine,也可以通过alter table语句来修改存储引擎。

create table tbl_user (

)engine=InnoDB default charset=utf-8;

alter table tbl_user engine = innodb;

猜你喜欢

转载自blog.csdn.net/vbirdbest/article/details/81051579