0

0

数据库再设计(DatabaseRedesign)

php中文网

php中文网

发布时间:2016-06-07 15:54:42

|

1337人浏览过

|

来源于php中文网

原创

数据库设计有三个来源:(1)可以从现有数据开始设计数据库,例如从excel表格等,这种模式下需要考虑的问题是数据的normalization,最终通常将数据转化为BCNF范式;(2)设计新的数据库,这种模式需要从构建E-R图开始一步步构造完整的数据库;(3)数据库再

数据库设计有三个来源:(1)可以从现有数据开始设计数据库,例如从excel表格等,这种模式下需要考虑的问题是数据的normalization,最终通常将数据转化为bcnf范式;(2)设计新的数据库,这种模式需要从构建e-r图开始一步步构造完整的数据库;(3)数据库再设计,这种模式需要修改现有数据库,使其满足新的数据或者性能要求。本博客介绍第三种数据库设计模式。此外,为了介绍数据库再设计,我们需要有一个现成的数据库。我们将以一个艺术品拍卖会的数据库为例介绍,图一描述了其数据库。

\

 

1. 数据库再设计目的

一般情况下,如果我们按照标准的模式从前两种来源设计数据库,最终的结果都是满足相关要求的,为什么还需要重新设计数据库?该问题的解答包含两方面:首先,正确地设计数据库其实非常难,尤其是从无到有的全新设计。即使我们获得了完整的用户需求,并创建了一个正确的数据模型,将模型转化为实际数据库依旧非常难,尤其模型非常复杂时。更重要的一方面是,用户的需求一直在变化,这直接导致数据库的不停变更。因而数据库再设计是数据库设计和维护中很重要的一部分,再设计过程会存在于数据库的整个生命周期。

2. 准备工作

在修改数据库结构之前,我们需要做一些准备工作。首要的任务是熟悉当前数据库的结构和存储的数据,以了解数据库中各结构的相互依赖关系。其次,在修改实际数据库之前,我们需要在相当数据量的测试数据库上进行测试,只有在测试数据库上保证正确之后才能实际修改可操作数据库(operational database)。最后,一定要备份可操作数据库。

3. 依赖图

在修改数据库结构之前,我们还需要构造一个依赖图(dependency graph),用来描述不同数据库结构之间的依赖关系。当我们在修改数据库的不同结构时,会影响其他结构,通过依赖图就可以很清楚地看出修改一个结构会影响哪些结构。图二描述了图一数据库中不同结构的依赖图。

\

 

假设我们现在需要修改artist表,则依赖于它的表work,触发器Trans_checkSalesPrice和视图ArtistWorkNetView也需要修改。根据实际情况,修改表work可能还会递归导致依赖于它的结构也需要修改。可以看出数据库再设计是一个相当复杂的过程。不过,通常情况下的修改只会导致子节点的变动,不太可能修改子子节点或者后续子节点。

数据库再设计通常包含三个方面的修改:表或关系、列和基数,下面详细介绍不同的修改。此外,本博客涉及的数据库再设计仅限于数据库数据的范围没有大到不能复制的程度。

1. 数据库表的修改

4.1表名的修改

单纯的表名修改没有想象中那么简单,会导致一系列结构的修改。例如,假设我们现在要将work表名改为WORK_VERSION2,我们需要执行下列步骤:

1) 利用CREATE TABLEWORK_VERSION2语句创建新的表,在work中workID是一个surrogate key,在WORK_VERSION2中暂时不将该主键设为surrogate key。同时将work表中的constraint复制到新表中,注意修改constraint的名字,否则会提示冲突。

2) 将work表中的数据利用insert into语句添加到新表中,添加语句包含work所有的列。

3) 修改WORK_VERSION2表中workID为surrogatekey。修改方式在不同的数据库产品上不同。

4) 修改触发器Trans_checkSalesPrice和视图ArtistWorkNetView,主要是将旧表名work改为新表名WORK_VERSION2。

5) 删除旧表work。删除时需要先将表trans中的外键约束删除,然后再删除work。

6) 在trans表上添加新的外键约束使其指向新表WORK_VERSION2的workID。

4.2 添加新表或关系

添加新表或者关系通常没有什么难点,直接利用create table创建新表并附加各种constraint即可。唯一的一点例外是,如果创建的新表是某个现存表的父节点(新表和现存表有1:N的最大基数关系),我们需要在现存表中添加外键约束。

4.3 删除表或关系

删除表通常遵循这样一个原则:首先删除依赖该表主键的外键约束,然后删除该表。当然,在删除过程中,视图和触发器也应该根据依赖图进行相应的修改或删除。

2. 数据库表中列的修改

列的修改本质上还是属于数据库表的修改,但是由于其本身含有较多内容,单独拿出来介绍。

5.1 列名的修改

如果修改的是一个nonkey形式的列,通常不会带来什么影响,但是还是需要检查是否有触发器或者视图依赖于该列,如果有也需要修改相应的列名。如果修改的是主键,除了检查视图和触发器,我们还需要将对应的外键名字也修改掉。

5.2 添加列

添加可以null的列直接采用alter table add column语句即可。在数据库运行的过程中,我们可以随时修改该列的属性,比如设置default值等。但是设置的default值只会存在于后续添加的行中,先前添加的行值可能还是null。

初次添加一个not null的列也是直接采用altertable add column语句。但是我们不能将其设置为not null,因为表中已经存在很多行,直接设置not null会报错。然后更新所有的行使其值为not null,然后再利用SQL语句ALTER TABLE ALTER COLUMN设置列属性为not null。

5.3 删除列

nonkey的列直接删除一般不会存在问题,但是还是需要注意视图和触发器。如果删除的是外键,则需要先删除外键对应的constraint,然后再删除外键对应的列。

当删除主键时,情况会复杂很多。例如我们要删除work表的主键,并替换为新的主键,则需要执行下列步骤:

1) 首先删除表trans中的外键约束WorkFK;

SONIFY.io
SONIFY.io

设计和开发音频优先的产品和数据驱动的解决方案

下载

2) 其次删除表work中的主键约束WorkPK;

3) 利用列(Title,Copy, ArtistID)创建新的主键约束WorkPK;

4) 在trans表中创建依赖于work中列(Title, Copy, ArtistID)的外键约束WorkFK;

5) 删除列workID。

5.4 修改列的数据类型或者约束

可以用命令ALTER TABLE ALTER COLUMN命令修改列的属性。如果将列由null变为not null,则必须确保所有的列都为not null。不同数据类型之间的转换可能导致数据丢失。但是通常情况下,将数字类型、时间、货币类型转换为char或者varchar都没有问题,反过来则可能不被DBMS允许。

添加删除constraint通过ALTER TABLEADD CONSTRAINT 和ALTER TABLE DROP CONSTRAINT语句完成。

3. 修改关系的基数(Cardinalities)

6.1 修改最小基数

parent端

修改parent端的最小基数,也就是让child表有或者没有parent,也即判断child中外键是否为null。例如,针对1:N的关系DEPARTMENT to EMPLOYEE,外键DepartmentNumber出现在employee中。修改employee是否需要指定department也即修改DepartmentNumber的null状态。

如果将最小基数从0改为1,就需要将外键设置为not null,这时需要确保目前存在的数据外键都为not null,否则我们需要先更新数据。根据不同的DBMS产品,修改外键的方式也不一样,但是可以遵循下面的步骤:

1) 删除旧的外键约束;

2) 设置外键列为not null;

3) 添加新的外键约束。

上面的例子修改最小基数的SQL语句如下:

ALTER TABLE EMPLOYEE
    DROP CONSTRAINT DepartmentFK;
ALTER TABLE EMPLOYEE
    ALTER COLUMN DepartmentNumber Int NOT NULL;
ALTER TABLE EMPLOYEE
    ADD CONSTRAINT DepartmentFK FOREIGN KEY (DepartmentNumber)
        REFERENCES DEPARTMENT (DepartmentNumber)    
	    ON UPDATE CASCADE;

级联属性需要根据具体的业务来确定。

child端

在child端设置最小基数非零需要利用触发器或者application code,因而将最小基数从零变为一也需要利用触发器。如果将最小基数从1变为0,直接删除触发器即可。

6.2 增大最大基数

1:1 to 1:N

假设在EMPLOYEE 和PARKING_PERMIT之间存在如图三所示的1:1关系,现在默认employee是parent,因为外键在parking_permit中。当将1:1的关系变为1:N的关系时,需要考虑哪端是parent端(为1)。假如employee还是parent端,则只需要将parking_permit中的外键unique属性去掉即可。如果parking_permit变为parent端,则我们需要将外键移到employee中,还需要数据导入employee表中。具体的操作如下:

1) 在employee中添加可以为null的外键PermitNumber;

2) 将parking_permit中的数据导入employee表中:
UPDATE EMPLOYEE
    SET EMPLOYEE.PermitNumber =
        (SELECT  PP.PermitNumber
         FROM  PARKING_PERMIT AS PP
         WHERE  PP.EmployeeNumber = EMPLOYEE.EmployeeNumber);

 

3) 将parking_permit中的外键EmployeeNumber删除;

4) 在employee中添加外键约束;

5) 修改相应的触发器和视图。

\

 

1:N to N:M 

将1:N的关系变为N:M的关系比较容易,只需要:创建一个只包含两个表主键的新表(intersection table),然后将两个主键的组合作为新表的主键,每一个分别是依赖于另外每一个表的外键;从child表导入数据,然后删除child中的外键约束。最后修改触发器和视图使其应用新表。

6.3 减小最大基数(存在数据丢失)

将一个N:M的关系降为一个1:N的关系,我们需要在child表中添加一个外键,然后从intersection table中导入外键的数据。修改相应的触发器和视图等,最后将intersection table删除。将一个1:N的关系降为1:1的关系,我们需要将child表中的外键数据变为1,然后将外键约束变为unique。这两种情况都需要决定如何删除数据。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

39

2026.02.06

java多线程方法汇总
java多线程方法汇总

本专题整合了java多线程面试题、实现函数、执行并发相关内容,阅读专题下面的文章了解更多详细内容。

17

2026.02.06

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

289

2026.02.06

快手网页版入口与电脑端使用指南 快手官方短视频观看入口
快手网页版入口与电脑端使用指南 快手官方短视频观看入口

本专题汇总了快手网页版的最新入口地址和电脑版使用方法,详细提供快手官网直接访问链接、网页端操作教程,以及如何无需下载安装直接观看短视频的方式,帮助用户轻松浏览和观看快手短视频内容。

150

2026.02.06

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

11

2026.02.06

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

7

2026.02.06

JavaScript 异步编程与事件驱动架构
JavaScript 异步编程与事件驱动架构

本专题深入讲解 JavaScript 异步编程与事件驱动架构,涵盖 Promise、async/await、事件循环机制、回调函数、任务队列与微任务队列、以及如何设计高效的异步应用架构。通过多个实际示例,帮助开发者掌握 如何处理复杂异步操作,并利用事件驱动设计模式构建高效、响应式应用。

11

2026.02.06

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

47

2026.02.05

java中fail含义
java中fail含义

本专题整合了java中fail的含义、作用相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 8.7万人学习

Django 教程
Django 教程

共28课时 | 4万人学习

Excel 教程
Excel 教程

共162课时 | 16.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号