总结
数据库,存储引擎,表,字段,索引
- 范式类型和大小默认为空和索引
要不要用数据库,用什么数据库,怎么用数据库
单体,分布式,数据类型,数据量,并发量,效率,安全
数据库只是数据的一种存储方式,也有一定的使用成本;某些情况下可以换一种数据存储方式,比如 JSON文件、Excel表格甚至txt文件
json存储和proto存储可以跨语言,json存储数据库类型是文本,proto格式存储是二进制
符合范式,加冗余(提高数据处理速度)
加索引
加视图(提高速度,表拆分后union视图)
安全:主从复制、mysql集群
效率:读写分离、分库分表、mysql集群
理论
E-R (entity-relationship):实体、属性、关联(1:1, 1:n, m:n)
CDM (Conceptual Data Model):概念数据模型
PDM (Physical Data Model):物理数据模型
1NF范式:
- 字段原子性,实体属性不可再分
2NF范式:
- 部分依赖,通过候选键可以直接区分每个非候选键
- 在1NF范式的基础上消除非主属性对主码的部分依赖
- 候选键:可以唯一标识每一行数据的属性,比如,id,id_card,tel_number
3NF范式:
- 传递依赖,任何非主属性不依赖于其它非主属性
- 在2NF基础上消除-传递依赖
注意
不用mysql关键字做字段名,表名称
不使用外键,使用代码保证表与表之间的一致性
数据库
数据库:存储引擎、编码、排序规则
存储引擎:MyISAM与InnoDB
名称 | 锁定 | 事务 | 索引 |
---|---|---|---|
InnoDB | 行锁定 | 支持 | 没有限制 |
MyISAM | 表锁定 | 不支持 | 最多64个索引, 索引中字段字节总和不得大于 1000 bytes |
Merge | 前提:MYISAM引擎&&表结构一致,支持单表唯一索引 |
编码:
- utf-8mb4 (most bytes 4bytes):英文使用1个字节,中文使用3个字节来编码;特殊字符表情,宽字符4字节;可以存储表情符号
- utf-8:英文及符号占1个字节,中文及符号占3个字节,数字一个字节
- unicode:中文、英文都是2个字节
- utf-16:一般英文和中文都要占用2个字节;unicode扩展区汉字占用4个字节
- utf-32:所有字符4个字节
排序规则:
排序规则 | 优点 | 缺点 | 其他 |
---|---|---|---|
utf8_general_ci | 效率较高 | 正确性差 | 能接受ß = s(单s)而不是ss(双ss)则使用;ß = s |
utf8_unicode_ci | 效率较低 | 正确性较高 | 德语和法语,utf8_unicode_ci工作的很好;ß = ss |
表
什么数据可以放到表里面
分类:基础表、扩展表、关联表
名称
参考网址
单表数据量大小控制在500万行以内
- 500万行不是mysql数据库的限制,修改表结构,备份,恢复限制
- 历史数据归档,解决日志数据过大
- 分库分表,解决表过大
谨慎使用mysql分区表,谨慎选择分区键??
- 逻辑上表现为一个表,物理上表现为多个文件
- 建议采用物理分表的方式管理大数据
禁止在mysql数据库中存储大的二进制文件
- 大文件往往需要随机IO操作太耗费时间
- mysql中存储地址URL即可
- 图片、文件存储于专用文件服务器
禁止在线上做数据库压力测试
关系
- 一对一:任意一方放入另一方的主键
- 一对多:在多的这一方放入一的这一方的主键
- 多对多:单独建表需要建立关联表
表/名称
前缀用于区分系统表和业务表
后缀代表表的分类
字段
字段
- 分类:业务字段和非业务字段(表操作字段)
- 字段类型和大小、默认为空和索引
- 字段名称,类型、有无符号,长度、宽度,默认值,允许为空,索引
- 主键、外键
- 冗余字段
设计
- 业务字段和非业务字段(表操作字段),id是用于操作表的字段,没有业务含义
- 使用程序代替外键
- 空间合适:
- 类型精确,多用int、char;
- 长度精确,固定长度;
- 有无符号 unsigned
- 避免使用 text,blob
- 字段类型越大,建立索引占用空间越多,一页框能存储的索引节点就越少,遍历时磁盘IO就越多
- 磁盘中的索引节点会载入内存中的页框
- 尽可能把所有列定义为not null
- 聚集索引的生成要求唯一且非空
字段/数据类型
参考网址
数据类型
类型名 | 存储大小 | 字节数 | 介绍 |
---|---|---|---|
bit | 存储bit值,0或1,长度最大64位 | ||
char | 宽度:0~85 | 0-255 bytes | 定长字符,显示变长,空间占用定长;255/3=85个汉字 |
varchar | 宽度:0~5000~2万 | 0-65535 bytes | 变长字符,显示变长,空间占用变长;65535/3=21845个汉字;阿里显示宽度最大5000 |
binary | 包含0或1字符 | ||
varbinary | 包含0或1字符 | ||
bigint | 8字节 | 无符号值:0 到约 10 的 19 次方 | 常用作主键 |
tinyint | 1字节 | 无符号值:0 到 255 | 常用作字典类型 |
int | 4字节 | 无符号值:0 到约 43 亿 | |
smallint | 2字节 | 无符号值:0 到 65535 | |
mediumint | 3字节 | 无符号:0到16777215(1千600万) | |
double | 8bytes | (2.22…E-308,1.79… E+308) | 双精度,浮点数 |
decimal(a,b) | 16bytes | a最大38,b在0~a之间 | decimal(10, 7):总长为10,小数长7 |
float | 4bytes | (1.17…E-38,3.40…E+38) | 单精度,浮点数 |
tinytext | 255bytes | 0-65 535 bytes | 255/3=85个汉字 |
text | 65535/1024=64K | 0-65535 bytes | 65535/3=21845个汉字,约2万汉字 |
mediumtext | 16777215/1024/1024=16M | 0-16 777 215 bytes | 16777215/3=5592405个汉字,559万汉字 |
longtext | 4294967295/1024/1024/1024=4G | 0-4 294 967 295 bytes | 4294967295/3=1431655765个汉字,14亿汉字 |
TINYBLOB | 255bytes | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
BLOB | 63.9KB | 0-65 535 bytes | 二进制形式的长文本数据 |
MEDIUMBLOB | 15.9MB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
LONGBLOB | 3.9GB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
注意:
- mysql varchar(3) 中的数字描述的是字符个数不是字节数:,不论中文 英文 数字 都是3个。
- 4.0版本以下,varchar(100),指的是100字节,如果存放UTF8汉字时,只能存33个(每个汉字3字节)
- 5.0版本以上,varchar(100),指的是100字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放100个。
- BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,前两个包含二进制字符串即包含字节字符串而不是字符字符串
- 整数类型只要设置了类型,存储大小由类型决定不由显示宽度决定
- navicat中整数类型后面括号中的数字,表示的是显示宽度,不表示存储长度,这点与 varchar、char 后面的数字含义是不同的。
- 经纬度:decimal(10, 7)只需要精确到小数点后 7 位,精度就是 1CM,因此,数据库保存经纬度采用 decimal(10, 7) 即可。
- 钱:decimal(15, 2)万亿.角分;或者直接到分的整数,
- 可以把小数和整数分开存储
- varchar:显示宽度最大5000
- bigint(20)自增做主键
- tinyint(0~255)做字典
- text:2万汉字
日期时间:
类型名 | 范围 | 格式 | 介绍 | 字节 |
---|---|---|---|---|
datetime | 1000-01-01 00:00:00/9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 阿里规范datatime;是否需要根据当前时间更新;为null存储为null | 8字节 |
timestamp | 1970-01-01 00:00:00/2038 | YYYYMMDD HHMMSS | 时间戳;timestamp会将时区存储进去;为null时为当前时间 | 4字节 |
time | ‘-838:59:59’/‘838:59:59’ | HH:MM:SS | ||
year | 1901/2155 | YYYY | ||
date | 1000-01-01/9999-12-31 | YYYY-MM-DD |
注意:
- 时间默认值:CURRENT_TIMESTAMP
- create_time使用datetime,只在创建时使用
- update_time使用datetime,更新时需要更新这个字段
字段/公共字段
部分
id(bigint(20),主键,自增,无符号)
create_time(datetime) :创建时使用1次
update_time(datetime) :根据当前时间更新,默认值CURRENT_TIMESTAMP
tenant_id(bigint(20),无符号):租户ID
全部
id(bigint(20),主键,自增,无符号)
create_time(datetime) :创建时使用1次
update_time(datetime) :根据当前时间更新,默认值CURRENT_TIMESTAMP
delete_time(datetime):删除时使用1次
create_by(char(30)):创建者
update_by(char(30)):更新者
delete_by(char(30)):删除者
tenant_id(bigint(20),无符号):租户ID
data_scope:同一租户下,数据的范围
is_enabled(tiny_int(1),无符号):注释:是否启用 1:true启用 0:flase停用 默认:1
is_deleted(tiny_int(1),无符号):注释:是否删除 1:true删除 0:false未删除 默认:0
字段/默认值
避免字段默认值带来业务意义
直接用字段默认值设置为常用值
字段/名称
主键
环境分类:单体、分布式
生成算法:UUID、雪花算法
生成方法:mysql自增、java代码生成、ORM框架生成
innoDB数据库引擎时,使用int自增做主键
分类 | 说明 |
---|---|
mysql自增主键 | innoDB |
mysql自带uuid | |
ORM框架自动插入雪花算法 | |
java生成uuid、雪花算法 |
- 设计经验:
- 使用自增主键;不方便获取数据库生成的id,框架会返回插入的数据对象
- 雪花算法:bigint(20)
- uuid:varchar(36)
外键
主表的主键作为从表的外键
删除时的约束:删除主表记录时,从表中的动作
- CASCADE(级联):删除主键表时,从表一并删除
- RESTRICT/NO ACTION:从表约束主表-主表中的记录在外键中有时,不可删除
- SET NULL:从表约束主表-主表中的记录在外键中有时,设置从表中该外键值为null
索引
- 索引建立,建立一个好的索引
- 联合索引左侧,放区分度高的(优先索引左侧),查询最频繁的,字段长度小的(1页能存储更多的索引节点)
- varchar字段建立索引,必须制定长度,长度=20时区分度=90%, count(distinct left(列名, 索引长度))/count(*)
- 索引使用,查询尽量使用到索引
- 建议单张表索引不超过5个
- 禁止给表中的每一列都建立单独的索引
- 每张表必须有主键
- 一般开发使用 普通索引和唯一索引就可以了
- 手机号设置唯一索引;身份证设置成唯一索引
- 与数据字典对应的表sys_dict 多建立索引
- 关联查询join字段建立索引
索引原理
- B+树
- 建立B+树的过程比较耗时
- 建立一颗好的B+树,有助于提高查询速度
索引名称:
- 主键索引:pk_ 字段名
- 唯一索引:uk_字段名
- 普通索引:idx_字段名
- 组合索引:idx_字段名1_字段名2
事务
分库分表
分库分表时机:523原则,单表行数超过 500 万行或者单表容量超过 2GB;预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
分库:请求发布到不同的库处理,同一条请求单表的压力没有降低。
分表:数量合适
分表/水平拆分
方法1和方法3结合的方式来进行分表
- 预先估计会出现大数据量并且访问频繁的表,将其分为若干个表:映射方法 表id-(hash算法、取余算法)-分表表名
- 事先没有想到怎么办
- 换用算法就破坏了对应关系
- merge存储引擎:TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST
- 先有几张存储引擎为MYISAM的表+他们的表结构一致
- 一个 merge 表不能在整个表上维持 unique 索引,只能在单个表上维持unique索引。当你执行一个 insert,数据进入那张分表(取决于 insert_method 选项的值)
分表/垂直拆分
按业务拆分,把业务拆分的更加细
例子
传递依赖:employee表中有depart_code,depart_name;depart表中有depart_code,depart_name;如果depart表中的depart_name改变了,employee表中depart_name怎么办
对象数据库:mysql是结构化数据库,图片和文件等二进制文件实体放到对象数据库中,mysql中放入链接地址即可
主键:mybatis-plus雪花算法默认int类型19位,所以设计数据库时bigint(20)
字段:树形目录所需字段,id parent
例子/数据字典
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_dict_type
-- ----------------------------
DROP TABLE IF EXISTS `sys_dict_type`;
CREATE TABLE `sys_dict_type` (
`dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键',
`dict_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典名称',
`dict_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典类型',
`status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`dict_id`) USING BTREE,
UNIQUE INDEX `dict_type`(`dict_type`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '字典类型表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Table structure for sys_dict_data
-- ----------------------------
DROP TABLE IF EXISTS `sys_dict_data`;
CREATE TABLE `sys_dict_data` (
`dict_code` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码',
`dict_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典类型',
`dict_label` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典标签',
`dict_value` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典键值',
`is_default` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'N' COMMENT '是否默认(Y是 N否)',
`dict_sort` int(11) NULL DEFAULT 0 COMMENT '字典排序',
`status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)',
`create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`dict_code`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 40 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '字典数据表' ROW_FORMAT = DYNAMIC;
SET FOREIGN_KEY_CHECKS = 1;
注意
- dict_type加上唯一前缀,区分不同业务的字典
参考文档
《阿里巴巴泰山版Java开发手册》