当前位置: 移动技术网 > IT编程>数据库>Mysql > MySQL基础篇(02):从五个维度出发,审视表结构设计

MySQL基础篇(02):从五个维度出发,审视表结构设计

2019年12月27日  | 移动技术网IT编程  | 我要评论
本文源码: "GitHub·点这里" || "GitEE·点这里" 一、数据场景 1、表结构简介 任何工具类的东西都是为了解决某个场景下的问题,比如Redis缓存系统热点数据,ClickHouse解决海量数据的实时分析,MySQL关系型数据库存储结构化数据。数据的存储则需要设计对应的表结构,清楚的表 ...

本文源码:github·点这里 || gitee·点这里

一、数据场景

1、表结构简介

任何工具类的东西都是为了解决某个场景下的问题,比如redis缓存系统热点数据,clickhouse解决海量数据的实时分析,mysql关系型数据库存储结构化数据。数据的存储则需要设计对应的表结构,清楚的表结构,有助于快速开发业务,和理解系统。表结构的设计通常从下面几个方面考虑:业务场景、设计规范、表结构、字段属性、数据管理。

2、用户场景

例如存储用户基础信息数据,通常都会下面几个相关表结构:用户信息表、单点登录表、状态管理表、支付账户表等。

  • 用户信息表

存储用户三要素相关信息:姓名,手机号,身份证,登录密码,邮箱等。

create table `ms_user_center` (
  `id` int(11) not null auto_increment comment '用户id',
  `user_name` varchar(20) not null comment '用户名',
  `real_name` varchar(20) default null comment '真实姓名',
  `pass_word` varchar(32) not null comment '密码',
  `phone` varchar(20) not null comment '手机号',
  `email` varchar(32) default null comment '邮箱',
  `head_url` varchar(100) default null comment '用户头像url',
  `card_id` varchar(32) default null comment '身份证号',
  `user_sex` int(1) default '1' comment '用户性别:0-女,1-男',
  `create_time` datetime default null comment '创建时间',
  `update_time` datetime default null comment '更新时间',
  `state` int(1) default '1' comment '是否可用,0-不可用,1-可用',
  primary key (`id`)
) engine=innodb default charset=utf8 comment='用户表';
  • 单点登录表

用意是在多个业务系统中,用户登录一次就可以访问所有相互信任的业务子系统,是聚合业务平台常用的解决方案。

create table `ms_user_sso` (
  `user_id` int(11) not null comment '用户id',
  `sso_id` varchar(32) not null comment '单点信息编号id',
  `sso_code` varchar(32) not null comment '单点登录码,唯一核心标识',
  `log_ip` varchar(32) default null comment '登录ip地址',
  `create_time` datetime default null comment '创建时间',
  `update_time` datetime default null comment '更新时间',
  `state` int(1) default '1' comment '是否可用,0-不可用,1-可用',
  primary key (`user_id`)
) engine=innodb default charset=utf8 comment='用户单点登录表';
  • 状态管理表

系统用户在使用时候可能出现多个状态,例如账户冻结、密码锁定等,把状态聚合到一起,可以更加方便的管理和验证。

create table `ms_user_status` (
  `user_id` int(11) not null comment '用户id',
  `account_status` int(1) default '1' comment '账户状态:0-冻结,1-未冻结',
  `real_name_status` int(1) default '0' comment '实名认证状态:0-未实名,1-已实名',
  `pay_pass_status` int(1) default '0' comment '支付密码是否设置:0-未设置,1-设置',
  `wallet_pass_status` int(1) default '0' comment '钱包密码是否设置:0-未设置,1-设置',
  `wallet_status` int(1) default '1' comment '钱包是否冻结:0-冻结,1-未冻结',
  `email_status` int(1) default '0' comment '邮箱状态:0-未激活,1-激活',
  `message_status` int(1) default '1' comment '短信提醒开启:0-未开启,1-开启',
  `letter_status` int(1) default '1' comment '站内信提醒开启:0-未开启,1-开启',
  `emailmsg_status` int(1) default '0' comment '邮件提醒开启:0-未开启,1-开启',
  `create_time` datetime default null comment '创建时间',
  `update_time` datetime default null comment '更新时间',
  `state` int(1) default '1' comment '是否可用,0-不可用,1-可用',
  primary key (`user_id`)
) engine=innodb default charset=utf8 comment='用户状态表';
  • 支付账户表

用户交易的核心表,存储用户相关的账户资金信息。

create table `ms_user_wallet` (
  `wallet_id` int(11) not null auto_increment comment '钱包id',
  `user_id` int(11) not null comment '用户id',
  `wallet_pwd` varchar(32) default null comment '钱包密码',
  `total_account` decimal(20,2) default '0.00' comment '账户总额',
  `usable_money` decimal(20,2) default '0.00' comment '可用余额',
  `freeze_money` decimal(20,2) default '0.00' comment '冻结金额',
  `freeze_time` datetime default null comment '冻结时间',
  `thaw_time` datetime default null comment '解冻时间',
  `create_time` datetime default null comment '创建时间',
  `update_time` datetime default null comment '更新时间',
  `state` int(1) default '1' comment '是否可用,0-不可用,1-可用',
  primary key (`wallet_id`)
) engine=innodb default charset=utf8 comment='用户钱包';

二、设计规范

1、涉及模块

通过上面几个表设计的案例,可以看到表设计关联到数据库的各个方面知识:数据类型,索引,编码,存储引擎等。表设计是一个很大的命题,不过也遵循一个基本规范:三范式。

2、三范式

  • 基础概念

一范式

表的列的具有原子性,不可再分解,即列的信息,不能分解,关系型数据库mysql、oracle等自动的满足。

二范式

每个事实的数据记录只会出现一次, 不会冗余, 通常设计一个主键来实现。

三范式

要求一个表中不包含已经存在于其它表的非主键信息,例如部门和员工的信息,员工表包含部门表的主键id,则可以关联获取相关信息,没必要在员工表保存相关信息。

  • 优缺点对比

范式化设计

范式化结构设计通常更新快,因为冗余数据较少,表结构轻巧,也更好的写入内存中。但是查询起来涉及到关联,代价非常高,非常损耗查询性能。

反范式化设计

所有的数据都在一张表中,避免关联查询,索引的有效性更高,但是数据的冗余性极高。

  • 建议结论

上述的两种设计方式在实际开发中都是不存在的,在实际开发中都是混合使用。比如汇总统计,缓存数据,都会基于反范式化的设计。

三、字段属性

合适的字段类型对于高性能来说非常重要,基本原则如下:简单的类型占用资源更少;在可以正确存储数据的情况下,选最小的数据类型。

1、数据类型选择

  • 整数类型

tinyint、smallint、mediumint、int、bigint,根据数据类型范围合理选择即可。

  • 实数类型

float、double、decimal,建议资金货币相关类型使用高精度decimal存储,或者把数据成倍扩大为整数,采用bigint存储,不过处理相对麻烦。

  • 字符类型

char、varchar,长度不确定建议采用varchar存储,不过varchar类型需要额外开销记录字符串长度。char适合存储短字符,或者定长字符串,例如md5的加密结构。

  • 时间类型

datetime、timestamp,datetime保存大范围的值,精度秒。timestamp以时间戳的格式,范围相对较小,效率也相对较高,所以通常情况建议使用。

mysql的字段类型有很多种,可以根据数据特性选择合适的,这里只描述常见的几种类型。

2、基础用法操作

  • 数据类型

修改字段类型

alter table ms_user_sso modify state char(1) default '0' ;

alter table ms_user_sso 
modify state int(1) default '1' comment '状态:0不可用,1可用';

修改名称位置

alter table ms_user_sso 
change log_ip login_ip varchar(32) after update_time ;
  • 索引使用

索引类型:主键索引,普通索引,唯一索引,组合索引,全文索引。这里演示普通索引的操作。mysql的核心模块,后续详说。

添加索引

alter table ms_user_wallet add index user_id_index(user_id) ;
create index state_index on ms_user_wallet(state) ;

查看索引

show index from ms_user_wallet;

删除索引

drop index state_index on ms_user_wallet ;

修改索引

不具有真正意义上的修改,可以把原有的索引删除之后,再次添加索引。

  • 外键关联

用处:外键关联的作用保证多个数据表的数据一致性和完整性,建表时先有主表,后有从表;删除数据表,需要先删从表,再删主表。复杂场景不建议使用,实际开发中用的也不多。

添加外键

alter table ms_user_wallet 
add constraint user_id_out_key foreign key(user_id) references ms_user_center(id) ;

删除外键

alter table ms_user_wallet drop foreign key user_id_out_key ;

四、表结构管理

1、查看结构

desc ms_user_status ;
show create table ms_user_status ;

2、字段结构

  • 添加字段
alter table ms_user_status 
add `delete_time` datetime default null comment '删除时间' ;
  • 删除字段
alter table ms_user_status drop column delete_time ;

3、修改表名

alter table ms_user_center rename ms_user_info ;

4、存储引擎

  • 存储引擎
select version() ; show engines ;

mysql 5.6 支持的存储引擎有innodb、myisam、memory、archive、csv、blackhole等。一般默认使用innodb,支持事务管理。该模块mysql核心,后续详解。

  • 修改引擎

数据量大的场景下,存储引擎修改是一个难度极大的操作,容易会导致表的特性变动,引起各种后续反应,后续会详说。

alter table ms_user_sso engine = myisam ;

5、修改编码

表字符集默认使用utf8,通用,无乱码风险,汉字3字节,英文1字节,utf8mb4是utf8的超集,有存储4字节例如表情符号时使用。

  • 查看编码
show variables like 'character%';
  • 修改编码
alter table ms_user_sso default character set utf8mb4; 

五、数据管理

1、增删改查

添加数据

insert into ms_user_sso (
    user_id,sso_id,sso_code,create_time,update_time,login_ip,state
)
values
    (
        '1','sso7637267','sso78631273612',
        '2019-12-24 11:56:57','2019-12-24 11:57:01','127.0.0.1','1'
    );

更新数据

update ms_user_sso set 
 user_id = '1',sso_id = 'sso20191224',sso_code = 'sso20191224',
 create_time = '2019-11-24 11:56:57',update_time = '2019-11-24 11:57:01',
 login_ip = '127.0.0.1',state = '1'
where user_id = '1';

查询数据

一般情况下都是禁止使用 select* 操作。

select user_id,sso_id,sso_code,create_time,update_time,login_ip,state 
from ms_user_sso where user_id = '1';

删除数据

delete from ms_user_sso where user_id = '2' ;

不带where条件,就是删除全部数据。原则上不允许该操作,优化篇会详解。truncate table也是清空表数据,但是占用的资源相对较少。

2、数据安全

  • 不可逆加密

这类加密算法,多用来做数据验证操作,比如常见的密码验证。

select md5('cicada')='94454b1241ad2cfbd0c44efda1b6b6ba' ;
select sha('cicada')='0501746a2e4fd34e1d14015fc4d58309585edc7d';
select password('smile')='*b4fb95d86dcfc3f33a3852714dc742c77504479d' ;
  • 可逆加密

安全性要求高的系统,需要做三级等保,对数据的安全性极高,数据在存储时必须加密入库,取出时候需要解密,这些就需要可逆加密。

select decode(encode('123456','key_salt'),'key_salt') ;
select aes_decrypt(aes_encrypt('cicada','salt123'),'salt123');

上述数据安全的管理,也可以基于应用系统的服务(代码)层进行处理,相对专业的流程是从数据生成源头处理,规避数据传递过程泄露,造成不必要的风险。

六、源代码地址

github·地址
https://github.com/cicadasmile/mysql-data-base
gitee·地址
https://gitee.com/cicadasmile/mysql-data-base

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网