第23篇 聊聊数据冗余

为了帮助您理解数据冗余以及如何处理冗余,我将提供一个简化的例子来说明数据冗余的概念,并展示如何通过规范化设计来减少冗余。MySQL为例。

### **案例描述**
假设我们正在设计一个简单的图书馆管理系统,最初未规范化的数据库设计可能包含两个表格:

1. `Books` 表格 - 存储书籍的基本信息
2. `Categories` 表格 - 存储各类别信息
3. 由于设计初期考虑不周,我们在每个类别下都有一堆书籍时,选择了在`Books`表中直接存储类别名称(冗余数据)。

**E-R 图示例**:
```plaintext
Books (BookID, Title, Author, CategoryName)
Categories (CategoryID, CategoryName)

关系线:
Books.CategoryName --> Categories.CategoryName
```

**未规范化的表结构**:

```sql

CREATE TABLE Books (
    BookID INT PRIMARY KEY,
    Title VARCHAR(100),
    Author VARCHAR(50),
    CategoryName VARCHAR(50)
);
CREATE TABLE Categories (
    CategoryID INT PRIMARY KEY,
    CategoryName VARCHAR(50)
);


```

**插入数据**:

```sql
-- 插入Categories

INSERT INTO Categories (CategoryID, CategoryName) VALUES
(1, 'Programming'),
(2, 'Literature');

-- 插入Books表,注意到CategoryName冗余

INSERT INTO Books (BookID, Title, Author, CategoryName) VALUES
(1, 'Learning MySQL', 'SOME_AUTHOR', 'Programming'),
(2, 'Great Expectations', 'Charles Dickens', 'Literature'),
(3, 'The Art of Computer Programming', 'Donald Knuth', 'Programming');


```

**展示表信息**:

```sql

SELECT * FROM Books;


+---------+----------------------+------------------+--------------+
| BookID | Title                | Author           | CategoryName |
+---------+----------------------+------------------+--------------+
| 1       | Learning MySQL       | SOME_AUTHOR      | Programming  |
| 2       | Great Expectations   | Charles Dickens  | Literature   |
| 3       | The Art of Computer...| Donald Knuth     | Programming  |
+---------+----------------------+------------------+--------------+

SELECT * FROM Categories;


+-------------+---------------+
| CategoryID | CategoryName  |
+-------------+---------------+
| 1           | Programming   |
| 2           | Literature    |
+-------------+---------------+
```

然而,在此设计中,`Books`表中的`CategoryName`是一个冗余字段,因为同样的信息已经在`Categories`表中存储过。这会导致更新异常问题,例如当类别名改变时,需要在多个地方更新相同的信息。

**规范化解决方案**:

可以通过引入关联表来减少冗余:

```sql

CREATE TABLE Books (
    BookID INT PRIMARY KEY,
    Title VARCHAR(100),
    Author VARCHAR(50),
    CategoryID INT,
    FOREIGN KEY (CategoryID) REFERENCES Categories(CategoryID)
);
CREATE TABLE Categories (
    CategoryID INT PRIMARY KEY,
    CategoryName VARCHAR(50)
);


```

然后,删除`Books`表中的`CategoryName`字段,并重新组织数据:

```sql
-- 更新Books

UPDATE Books SET CategoryID = 1 WHERE CategoryName = 'Programming';
UPDATE Books SET CategoryID = 2 WHERE CategoryName = 'Literature';

-- 删除冗余字段

ALTER TABLE Books DROP COLUMN CategoryName;

-- 再次插入或更新Books

INSERT INTO Books (BookID, Title, Author, CategoryID) VALUES
(1, 'Learning MySQL', 'SOME_AUTHOR', 1),
(2, 'Great Expectations', 'Charles Dickens', 2),
(3, 'The Art of Computer Programming', 'Donald Knuth', 1);


```

现在表结构不再包含冗余数据,而是通过外键关联来确保数据的一致性。

 

接下来,我们可以查看规范化后的表信息并进行查询以验证数据的正确性。

**展示规范化后表的信息**:

```sql

SELECT * FROM Books;


+---------+----------------------+-----------------+------------+
| BookID | Title                | Author          | CategoryID |
+---------+----------------------+-----------------+------------+
| 1       | Learning MySQL       | SOME_AUTHOR     | 1          |
| 2       | Great Expectations   | Charles Dickens | 2          |
| 3       | The Art of Computer...| Donald Knuth    | 1          |
+---------+----------------------+-----------------+------------+

SELECT * FROM Categories;


+-------------+---------------+
| CategoryID | CategoryName  |
+-------------+---------------+
| 1           | Programming   |
| 2           | Literature    |
+-------------+---------------+
```

现在,如果要获取一本书所属的类别名称,可以使用JOIN操作来合并两个表的数据:

```sql

SELECT b.BookID, b.Title, c.CategoryName
FROM Books b
JOIN Categories c ON b.CategoryID = c.CategoryID;


```

结果如下:

```plaintext
+---------+----------------------+--------------+
| BookID | Title                | CategoryName |
+---------+----------------------+--------------+
| 1       | Learning MySQL       | Programming  |
| 2       | Great Expectations   | Literature   |
| 3       | The Art of Computer...| Programming  |
+---------+----------------------+--------------+
```

这样,我们就通过消除冗余和引入关联表的方式改进了数据库设计,使得数据更易于维护和管理,同时也避免了数据一致性的问题。

除此之外,规范化设计还有以下优势:

1. **节省存储空间**:在大量数据的情况下,重复存储同一类别的名称会浪费大量的存储空间。通过引入关联表,只需在`Categories`表中存储一次类别名称。

2. **提高数据完整性**:若在未规范化的设计中,手动修改某个类别的名称可能导致部分书籍记录未能同步更新。而在规范化设计中,只需更改`Categories`表中的数据,所有关联的书籍记录都会自动反映新的类别名称。

3. **增强数据一致性**:通过外键约束,可以确保在`Books`表中引用的`CategoryID`必须存在于`Categories`表中,从而防止无效数据的插入。

4. **优化查询性能**:虽然对于某些特定查询,如只查询某类别的所有书籍,未规范化的设计可能会更快,但在大多数情况下,尤其是涉及大量数据和复杂查询时,规范化设计能更好地支持索引和更高效的查询计划。

总结来说,通过上述图书馆管理系统的案例,我们展示了数据冗余问题及其对数据库设计的影响,并通过规范化方法消除了冗余,提高了数据完整性和查询效率。在实际应用中,根据具体需求和场景,可能需要权衡规范化程度与查询性能、存储成本等因素,以达到最佳的设计效果。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值