MySQL基础篇(02):从五个维度出发,审视表结构设计
本文源码: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
MySQL基础篇(02):从五个维度出发,审视表结构设计的更多相关文章
- MySQL进阶篇(02):索引体系划分,B-Tree结构说明
本文源码:GitHub·点这里 || GitEE·点这里 一.索引简介 1.基本概念 首先要明确索引是什么:索引是一种数据结构,数据结构是计算机存储.组织数据的方式,是指相互之间存在一种或多种特定关系 ...
- 【目录】mysql 基础篇系列
随笔分类 - mysql 基础篇系列 mysql 开发基础系列22 SQL Model(带迁移事项) 摘要: 一.概述 与其它数据库不同,mysql 可以运行不同的sql model 下, sql m ...
- 重新整理 mysql 基础篇————— 介绍mysql[一]
前言 准备整理mysql的基础篇了,前面整理了sql语句序列的的<sql 语句系列(八百章)>,感觉很多用不上,就停下来了,后续还是会继续整理. mysql 基础篇主要是对一些基础进行整理 ...
- 《手把手教你》系列基础篇(九十五)-java+ selenium自动化测试-框架之设计篇-java实现自定义日志输出(详解教程)
1.简介 前面宏哥一连几篇介绍如何通过开源jar包Log4j.jar.log4j2.jar和logback实现日志文件输出,Log4j和logback确实很强大,能生成三种日志文件,一种是保存到磁盘的 ...
- mysql基础篇 - 其他基本操作
基础篇 - 其他基本操作 其他基本操作 一.实验简介 本节实验中我们将学习并实践数据库的其他基本操作:索引.视图,导入和导出,备份和恢复等. 这些概念对于数据库管理员而言都非常重要,请 ...
- mysql基础篇 - 数据库及表的修改和删除
基础篇 - 数据库及表的修改和删除 修改和删除 一.实验简介 本节实验中,我们将学习并实践如何对数据库的内容做修改,删除,重命名等操作. 二.实验准备 在正式开始本实验内容之前,需要先 ...
- mysql基础篇 - SELECT 语句详解
基础篇 - SELECT 语句详解 SELECT语句详解 一.实验简介 SQL 中最常用的 SELECT 语句,用来在表中选取数据,本节实验中将通过一系列的动手操作详细学习 SELEC ...
- Linux服务-mysql基础篇
目录 1. 关系型数据库介绍 1.1 数据结构模型 1.2 RDBMS专业名词 1.3 关系型数据库的常见组件 1.4 SQL语句 2. mysql安装与配置 2.1 mysql安装 2.2 mysq ...
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
概要 本章,我们学习“常用的实现多线程的2种方式”:Thread 和 Runnable.之所以说是常用的,是因为通过还可以通过java.util.concurrent包中的线程池来实现多线程.关于线程 ...
随机推荐
- 类加载之 <clinit>() 和 <init>()
前序文章:深入理解Java类加载 <clinit>() 与 <init>() 区别 一.<clinit>() Java 类加载的初始化过程中,编译器按语句在源文件中 ...
- C++对于C故有问题的改进
C++继承了所有的C特性,并且提供了更丰富的语法和特性(OOP支持.模板支持等),并且拥有和C语言同样出色的运行效率.针对C语言的固有问题,C++做出了如下的升级: 所有变量都可以在需要使用时再定义( ...
- java架构之路-(netty专题)netty的基本使用和netty聊天室
上次回顾: 上次博客,我们主要说了我们的IO模型,BIO同步阻塞,NIO同步非阻塞,AIO基于NIO二次封装的异步非阻塞,最重要的就是我们的NIO,脑海中应该有NIO的模型图. Netty概念: Ne ...
- gRPC初识
RPC算是近些年比较火热的概念了,随着微服务架构的兴起,RPC的应用越来越广泛.本文介绍了RPC和gRPC的相关概念,并且通过详细的代码示例介绍了gRPC的基本使用. RPC是什么 在分布式计算,远程 ...
- 牛客练习赛52 B Galahad (树状数组)
题目链接:https://ac.nowcoder.com/acm/contest/1084/B 题意 5e5的区间,5e5个询求[l,r]区间内出现过的数的和 思路 1s时限,莫队显然会T 我们可以将 ...
- Docker容器到底是什么?
Docker是一个开源的应用容器引擎,是近些年最火的技术之一,Docker公司从Docker项目开源之后发家致富把公司商标改为了Docker,收购了fit项目,整合为了docker-compose,前 ...
- 基于 Google-S2 的地理相册服务实现及应用
马蜂窝技术原创内容,更多干货请关注公众号:mfwtech 随着智能手机存储容量的增大,以及相册备份技术的普及,我们可以随时随地用手机影像记录生活,在手机中存储几千张甚至上万张照片已经是很常见的事情.但 ...
- 【Bullet引擎】刚体类 —— btRigidBody
btRigidBody类主要用于刚体数据的计算. 在模拟刚体动画过程中,可以使用btRigidBody类获取所保存的刚体对象,进而控制刚体对象的旋转和位移.进行刚体模拟计算需要经常用到此类. API: ...
- java jni 调用c语言函数
今日在hibernate源代码中遇到了native关键词,甚是陌生,就查了点资料,对native是什么东西有了那么一点了解,并做一小记. native关键字说明其修饰的方法是一个原生态方法,方法对应的 ...
- Iperf 网络性能测试
1.iperf安装 1.1将iperf_PC.rar工具解压放在默认的盘目录下即可,无需安装 1.2安装iperf for android 2.06.apk"到手机端. adb instal ...