1. 为什么要进行数据库表设计
数据库表是存放数据的地方,遵循一定规律设计的数据库表,才能进行数据读取,方便数据管理。否则就像进入杂乱的仓库取东西一样,没法找到
2. 数据库表的设计
用户表:{用户编号(PK),用户名,密码,用户类别, 所属专业号(FK)}
课程表:{课程编号(PK),课程名,用户编号(FK) ,学分}
院 系:{院系编号(PK),院名}
专 业:{专业号(PK),专业名称 ,专业简介 ,总学时,所属院号(FK)}
参考书:{索书号(PK),课程编号(FK),ISBN/ISSN,责任者,出版日期,校图书馆连接地址,电子书连接地址}
专业课程表{专业号,课程编号} 联合主键
3. 数据库表结构设计,常见的数据库管理系统
一、数据场景 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')='' ; SELECT SHA('cicada')=''; SELECT PASSWORD('smile')='*' ; 可逆加密
安全性要求高的系统,需要做三级等保,对数据的安全性极高,数据在存储时必须加密入库,取出时候需要解密,这些就需要可逆加密。
SELECT DECODE(ENCODE('123456','key_salt'),'key_salt') ; SELECT AES_DECRYPT(AES_ENCRYPT('cicada','salt123'),'salt123');
上述数据安全的管理,也可以基于应用系统的服务(代码)层进行处理,相对专业的流程是从数据生成源头处理,规避数据传递过程泄露,造成不必要的风险。
4. 说明在设计数据库表时你是如何考虑的
数据库是整个软件应用的根基,是软件设计的起点,它起着决定性的质变作用,因此我们必须对数据库设计高度重视起来,培养设计良好数据库的习惯,是一个优秀的软件设计师所必须具备的基本素质条件! 那么我们要做到什么程度才是对的呢?下面就说说数据库设计的原则: (1)、数据库设计最起码要占用整个项目开发的40%以上的时间
数据库是需求的直观反应和表现,因此设计时必须要切实符合用户的需求,要多次与用户沟通交流来细化需求,将需求中的要求和每一次的变化都要一一体现在数据库的设计当中。如果需求不明确,就要分析不确定的因素,设计表时就要事先预留出可变通的字段,正所谓“有备无患”。 (2)、数据库设计不仅仅停留于页面demo的表面 页面内容所需要的字段,在数据库设计中只是一部分,还有系统运转、模块交互、中转数据、表之间的联系等等所需要的字段,因此数据库设计绝对不是简单的基本数据存储,还有逻辑数据存储。 (3)、数据库设计完成后,项目80%的设计开发在你脑海中就已经完成了 每个字段的设计都是有他必要的意义的,你在设计每一个字段的同时,就应该已经想清楚程序中如何去运用这些字段,多张表的联系在程序中是如何体现的。换句话说,你完成数据库设计后,程序中所有的实现思路和实现方式在你的脑海中就已经考虑过了。如果达不到这种程度,那当进入编码阶段后,才发现要运用的技术或实现的方式数据库无法支持,这时再改动数据库就会很麻烦,会造成一系列不可预测的问题。 (4)、数据库设计时就要考虑到效率和优化问题 一开始就要分析哪些表会存储较多的数据量,对于数据量较大的表的设计往往是粗粒度的,也会冗余一些必要的字段,已达到尽量用最少的表、最弱的表关系去存储海量的数据。并且在设计表时,一般都会对主键建立聚集索引,含有大数据量的表更是要建立索引以提供查询性能。对于含有计算、数据交互、统计这类需求时,还要考虑是否有必要采用存储过程。 (5)、添加必要的(冗余)字段 像“创建时间”、“修改时间”、“备注”、“操作用户IP”和一些用于其他需求(如统计)的字段等,在每张表中必须都要有,不是说只有系统中用到的数据才会存到数据库中,一些冗余字段是为了便于日后维护、分析、拓展而添加的,这点是非常重要的,比如黑客攻击,篡改了数据,我们便就可以根据修改时间和操作用户IP来查找定位。 (6)、设计合理的表关联 若多张表之间的关系复杂,建议采用第三张映射表来关联维护两张表之间的关系,以降低表之间的直接耦合度。若多张表涉及到大数据量的问题,表结构尽量简单,关联也要尽可能避免。 (7)、设计表时不加主外键等约束性关联,系统编码阶段完成后再添加约束性关联 这样做的目的是有利于团队并行开发,减少编码时所遇到的问题,表之间的关系靠程序来控制。编码完成后再加关联并进行测试。不过也有一些公司的做法是干脆就不加表关联。 (8)、选择合适的主键生成策略
5. 数据库表的设计
腊桥悔1、若是一对多或多对一的对象存到数据库表,原则上应该先观察对象的基本属性,然后设计一个数据表保存此对象的轮正基本数据,并在数量关系多的一方,加外键描述数据之间的关系;
2、若是多对多对象的数据库表,原则上也是观察该对象的基本属性,然后设计一个表来保存此对象的基本数据,且需要加一个中间表来描述数据的关系;
3、若是一对一的消岁对象的数据库设计, 除了上述操作,还因为一对一的对象有主从关系,因此可加入自连接表进行设计。
6. 数据库表结构设计
1.典型地质遗迹基本概况表
包括地理位置、园区范围、自然条件等组成(表6-2)。
表6-2 基本概版况(JBGK.MDB)数据库结构表
数据项说明:
地质权公园编号:前3位国别代码,按行政区划代码(GB/T2260-98)填写,后3位地质遗迹点的顺序号。当公园范围较大,跨国界时,其编号以主景区所在的区域为准进行编号,后6位为顺序号,保证地质遗迹编号的唯一性。
地质遗迹分类:为适应现阶段地质遗迹的调查,地质公园建设和发展规划、科学普及的开展,以系统地球科学理论为指导,赵汀(2009)提出了显性地质遗迹的概念并建立了学科分类系统,并在此基础上完成了中国国家地质公园地质遗迹分类。
2.景区、景点数据(表6-3,表6-4)
表6-3 景区表结构(JQ.MDB)表
表6-4 景点表结构(JD.MDB)表
景区和景点数据关系(表6-5)为一对多关系。即,一个景区至少有一处以上的景点,任意一个景点只能属于某一个景区。
7. 数据库进阶:循序渐进讲解数据表的十二个设计原则
数据表的设计原则:
( )不应针对整个系统进行数据库设计 而应该根据系统架构中的组件划分 针对每个组件所处理的业务进行组件单元的数据库设计;不同组件间所对应的数据库表之间的关联应尽可能减少 如果不同组件间的表需要外键关联也尽量不要创建外键关联 而只是记录关联表的一个主键 确保组件对应的表之间的独立性 为系统或表结构的重构提供可能性
( )采用领域模型驱动的方式和自顶向下的思路进行数据库设计 首先分析系统业务 根据职责定义对象 对象要符合封装的特性 确保与职责相关的数据项被定义在一个对象之内 这些数据项能够完整描述该职责 不会出现职责描述缺失 并且一个对象有且只有一项职责 如果一个对象要负责两个或两个以上的职责 应进行分拆
( )根据建立的领域模型进行数据库表的映射 此时应参考数据库设计第二范式 一个表中的所有非关键字属性都依赖于整个关键字 关键字可以是一个属性 也可以是多个属性的集合 不论那种方式 都应确保关键字能够保证唯一性 在确定关键字时 应保证关键字不会参与业务且不会出现更新异常 这时 最优解决方案为采用一个自增数值型属性或一个随机字符串作为表的关键字
( )由于第一点所述的领域模型驱动的方式设计数据库表结构 领域模型中的每一个对象只有一项职责 所以对象中的数据项不存在传递依赖 所以 这种思路的数据库表结构设计从一开始即满足第三范式 一个表应满足第二范式 且属性间不存在传递依赖
( )同样 由于对象职责的单一性以及对象之间的关系反映的是业务逻辑之间的关系 所以在领域模型中的对象存在主对象和从对象之分 从对象是从 N或困饥N N的角度进一步主对象的业务逻辑 所以从对象及对象关系映射为的表及表关联关系不存在删除和插入异常
( )在映射后得出的数据库表结构中 应再根据第四范式进行进一步修改 确保不存在多值依赖 这时 应根据反向工程的思路反馈给领域模型 如果表结构中存在多值依赖 则证明领域模型中的对象具有至少两个以上的职责 应根据返李第一条进行设计修正 第四范式 一个表如果满足BCNF 不应存在多值依赖
( )在经过分析后确认所有的表都满足二 三 四范式的情况下 表和表之间的关联尽量采用弱关联以便于对表字段和表结构的调整和重构 并且 我认为数据库中的表是用来持久化一个对象实例在特定时间及特定条件下的状态的 只是一个存储介质 所以 表和表之间也不应用强关联来表述业务(数据间的一致性) 这一职责应由系统的逻辑层来保证 这种方式也确保了系统对于不正确数据(脏数据)的兼容性 当然 从整个系统的角度来说我们还是要尽最大努力确保系统不会产生脏数据 单从另一个角度来说 脏数据的产生在一定程度上也是不可避免的 我们也要保证系统对这种情况的容错性 这是一个折中的方案
( )应针对所有表的主键和外键建立索引 有针对性的(针对一些大漏尺迟数据量和常用检索方式)建立组合属性的索引 提高检索效率 虽然建立索引会消耗部分系统资源 但比较起在检索时搜索整张表中的数据尤其时表中的数据量较大时所带来的性能影响 以及无索引时的排序操作所带来的性能影响 这种方式仍然是值得提倡的
( )尽量少采用存储过程 目前已经有很多技术可以替代存储过程的功能如 对象/关系映射 等 将数据一致性的保证放在数据库中 无论对于版本控制 开发和部署 以及数据库的迁移都会带来很大的影响 但不可否认 存储过程具有性能上的优势 所以 当系统可使用的硬件不会得到提升而性能又是非常重要的质量属性时 可经过平衡考虑选用存储过程
( )当处理表间的关联约束所付出的代价(常常是使用性上的代价)超过了保证不会出现修改 删除 更改异常所付出的代价 并且数据冗余也不是主要的问题时 表设计可以不符合四个范式 四个范式确保了不会出现异常 但也可能由此导致过于纯洁的设计 使得表结构难于使用 所以在设计时需要进行综合判断 但首先确保符合四个范式 然后再进行精化修正是刚刚进入数据库设计领域时可以采用的最好办法
( )设计出的表要具有较好的使用性 主要体现在查询时是否需要关联多张表且还需使用复杂的SQL技巧
lishixin/Article/program/SQL/201311/16156
8. 数据表设计考虑哪些问题
OK我来说几句 下面是数据库设计过程中我们要注意的问题,和要遵循的原则1. 原始单据和实体的间关系
可以是对、对多、多对多关系在般情况下它们是对关系:即张原始单据对应且只对应个实体在特殊情况下它
们可能是对多或多对关系即张原始单证对应多个实体或多张原始单证对应个实体这里实体可以理解为基本表明
确这种对应关系后对我们设计录入界面大有好处
〖例1〗:份员工履历资料在人力资源信息系统中就对应 3个基本表:员工基本情况表、社会关系表、工作简
历表这就是“张原始单证对应多个实体”典型例子
2. 主键和外键
般而言个实体不能既无主键又无外键在E—R 图中, 处于叶子部位实体, 可以定义主键也可以不定义主键(它
无子孙), 但必须要有外键(它有父亲)
主键和外键设计在全局数据库设计中占有重要地位当全局数据库设计完成以后有个美国数据库设计专家说
:“键到处都是键除了键的外什么也没有”这就是他数据库设计经验的谈也反映了他对信息系统核心(数据模型
)高度抽象思想:主键是实体高度抽象主键和外键配对表示实体的间连接
3. 基本表性质
基本表和中间表、临时表区别它具有如下 4个特性:
(1) 原子性基本表中字段是不可再分解
(2) 原始性基本表中记录是原始数据(基础数据)记录
(3) 演绎性由基本表和代码表中数据可以派生出所有输出数据
(4) 稳定性基本表结构是相对稳定表中记录是要长期保存
理解基本表性质后在设计数据库时就能将基本表和中间表、临时表区分开来
4. 范式标准
基本表及其字段的间关系, 应尽量满足第 3范式但是满足第 3范式数据库设计往往不是最好设计为了提高数
据库运行效率常常需要降低范式标准:适当增加冗余达到以空间换时间目
〖例2〗:有张存放商品基本表如表1所示“金额”这个字段存在表明该表设计不满足第 3范式“金额”可以
由“单价”乘以“数量”得到介绍说明“金额”是冗余字段但是增加“金额”这个冗余字段可以提高查询统计
速度这就是以空间换时间作法
在Rose 2002中规定列有两种类型:数据列和计算列“金额”这样列被称为“计算列”而“单价”和“数量
”这样列被称为“数据列”
表1 商品表表结构
商品名称 商品型号 单价 数量 金额
电视机 29吋 2,500 40 100,000
5. 通俗地理解 3个范式
通俗地理解 3个范式对于数据库设计大有好处在数据库设计中为了更好地应用 3个范式就必须通俗地理 最后说一下 如果项目的表在500个左右的话 数据可以有些冗余的 这样可以大大的提高程序的运行效率如果这个项目要有很强的扩展性 请严格遵守 第三范式 3NF 其实理论上这么讲,在正正开发中我们还是要根据实际情况来取舍的祝你好运!