1.2.1 数据库的基本概念
1.2.1.1 什么是数据库
数据库(Database)是按照一定的数据结构组织、存储和管理数据的集合。它可以被看作是一个电子化的文件柜,用户可以对文件中的数据进行添加、删除、修改、查询等操作。
数据库的主要特点包括:
- 结构化数据存储:数据按照一定的格式组织,便于管理和查询
- 高效的数据访问:支持快速检索和更新数据
- 数据共享:多个用户可以同时访问和使用数据库
- 数据一致性:确保数据的准确性和完整性
- 数据安全性:提供访问控制和数据保护机制
1.2.1.2 数据库管理系统
数据库管理系统(Database Management System,DBMS)是用于管理数据库的软件系统,它提供了数据定义、数据操作、数据存储、数据安全等功能。
常见的关系型数据库管理系统包括:
- PostgreSQL:开源免费的关系型数据库,功能强大
- MySQL:广泛使用的开源关系型数据库
- Oracle:企业级商业关系型数据库
- SQL Server:微软开发的商业关系型数据库
- SQLite:轻量级的嵌入式关系型数据库
1.2.1.3 数据库系统的组成
一个完整的数据库系统包括:
- 数据库:存储数据的集合
- 数据库管理系统:管理数据库的软件
- 数据库应用程序:用户与数据库交互的界面
- 数据库管理员(DBA):负责数据库的设计、维护和管理
- 用户:使用数据库的人员
1.2.2 关系型数据库模型
1.2.2.1 关系模型的基本概念
关系型数据库基于关系模型理论,该理论由IBM研究员埃德加·科德(Edgar F. Codd)于1970年提出。关系模型将数据组织成二维表格形式,通过行和列来表示数据。
关系模型的基本概念包括:
- 关系(Relation):即二维表格,对应数据库中的表
- 元组(Tuple):表格中的一行,对应数据库中的记录
- 属性(Attribute):表格中的一列,对应数据库中的字段
- 域(Domain):属性的取值范围
- 关系模式:关系的结构描述,包括关系名和属性列表
- 主键(Primary Key):唯一标识关系中每条元组的属性或属性组合
- 外键(Foreign Key):用于关联两个关系的属性,指向另一个关系的主键
1.2.2.2 关系模型的特点
关系模型具有以下特点:
- 数据结构化:数据以表格形式组织,结构清晰
- 数据独立性:数据与应用程序相互独立,便于维护和扩展
- 关系的规范性:遵循规范化理论,减少数据冗余
- 强大的查询能力:使用SQL语言进行数据操作
- 事务支持:确保数据的一致性和可靠性
1.2.2.3 关系完整性约束
关系完整性约束用于确保数据库中的数据准确、一致和有效。主要包括:
-
实体完整性:
- 主键不能为空
- 主键的值必须唯一
- 例如:
student_id作为学生表的主键,不能为空且必须唯一
-
参照完整性:
- 外键必须指向另一个关系的主键
- 外键可以为空
- 例如:学生表中的
class_id外键必须指向班级表中的class_id主键
-
用户定义完整性:
- 根据业务需求定义的约束
- 例如:学生的年龄必须大于0,成绩必须在0-100之间
1.2.3 SQL语言概述
1.2.3.1 SQL的定义
SQL(Structured Query Language,结构化查询语言)是用于管理关系型数据库的标准语言。它可以用于:
- 查询数据
- 插入、更新和删除数据
- 创建、修改和删除数据库对象(表、索引、视图等)
- 管理数据库权限
SQL具有以下特点:
- 非过程化:只需要指定做什么,不需要指定怎么做
- 统一标准:大部分关系型数据库都支持SQL标准
- 简单易用:语法简洁,易于学习和使用
- 功能强大:支持复杂查询和数据操作
1.2.3.2 SQL的分类
SQL可以分为以下几类:
-
数据定义语言(DDL):
- 用于创建、修改和删除数据库对象
- 主要命令:
CREATE、ALTER、DROP、TRUNCATE
-
数据操作语言(DML):
- 用于查询、插入、更新和删除数据
- 主要命令:
SELECT、INSERT、UPDATE、DELETE
-
数据控制语言(DCL):
- 用于管理数据库权限和事务
- 主要命令:
GRANT、REVOKE、COMMIT、ROLLBACK
-
事务控制语言(TCL):
- 用于管理事务
- 主要命令:
BEGIN、COMMIT、ROLLBACK、SAVEPOINT
1.2.3.3 SQL的基本语法
1.2.3.3.1 创建表
sql
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
student_name VARCHAR(50) NOT NULL,
age INTEGER CHECK (age > 0),
gender VARCHAR(10),
class_id INTEGER,
FOREIGN KEY (class_id) REFERENCES classes(class_id)
);
CREATE TABLE classes (
class_id SERIAL PRIMARY KEY,
class_name VARCHAR(50) NOT NULL,
teacher_name VARCHAR(50)
);
1.2.3.3.2 插入数据
sql
-- 插入单条数据
INSERT INTO classes (class_name, teacher_name) VALUES ('一班', '张老师');
-- 插入多条数据
INSERT INTO students (student_name, age, gender, class_id) VALUES
('张三', 18, '男', 1),
('李四', 17, '女', 1),
('王五', 18, '男', NULL);
1.2.3.3.3 查询数据
sql
-- 查询所有数据
SELECT * FROM students;
-- 查询指定列
SELECT student_name, age, gender FROM students;
-- 带条件查询
SELECT * FROM students WHERE age > 17;
-- 排序查询
SELECT * FROM students ORDER BY age DESC;
-- 限制结果数量
SELECT * FROM students LIMIT 10;
-- 关联查询
SELECT s.student_name, c.class_name, c.teacher_name
FROM students s
LEFT JOIN classes c ON s.class_id = c.class_id;
1.2.3.3.4 更新数据
sql
-- 更新单条数据
UPDATE students SET age = 19 WHERE student_id = 1;
-- 更新多条数据
UPDATE students SET gender = '男' WHERE gender IS NULL;
1.2.3.3.5 删除数据
sql
-- 删除单条数据
DELETE FROM students WHERE student_id = 3;
-- 删除多条数据
DELETE FROM students WHERE age < 18;
1.2.4 数据库设计原则
1.2.4.1 数据库设计的重要性
良好的数据库设计是构建高效、可靠、易于维护的数据库应用的基础。糟糕的数据库设计可能导致:
- 数据冗余和不一致
- 查询性能低下
- 难以扩展和维护
- 应用程序开发困难
1.2.4.2 数据库设计的步骤
数据库设计通常包括以下步骤:
- 需求分析:了解业务需求,确定数据范围和使用方式
- 概念设计:设计ER模型,描述实体、属性和关系
- 逻辑设计:将ER模型转换为关系模式,应用规范化理论
- 物理设计:选择存储结构和索引,优化性能
- 数据库实施:创建数据库和表,插入测试数据
- 数据库运行与维护:监控数据库性能,进行优化和调整
1.2.4.3 ER模型设计
ER(Entity-Relationship,实体-关系)模型是数据库概念设计的常用工具,用于描述实体、属性和实体之间的关系。
1.2.4.3.1 ER模型的基本元素
- 实体(Entity):现实世界中可以独立存在的事物,例如学生、班级、课程
- 属性(Attribute):实体的特征,例如学生的姓名、年龄、性别
- 关系(Relationship):实体之间的联系,例如学生与班级的关系
1.2.4.3.2 实体之间的关系类型
- 一对一关系(1:1):一个实体实例对应另一个实体的一个实例,例如一个学生对应一个学生证
- 一对多关系(1:N):一个实体实例对应多个另一个实体的实例,例如一个班级对应多个学生
- 多对多关系(M:N):多个实体实例对应多个另一个实体的实例,例如一个学生可以选多门课程,一门课程可以被多个学生选
1.2.4.3.3 ER模型示例
学生 (学生ID, 姓名, 年龄, 性别)
班级 (班级ID, 班级名称, 班主任)
课程 (课程ID, 课程名称, 学分)
选课 (学生ID, 课程ID, 成绩)
关系:
学生 - 班级:多对一
学生 - 课程:多对多(通过选课表关联)
1.2.4.4 数据库规范化
数据库规范化是一种设计数据库的方法,通过分解关系模式来减少数据冗余和避免数据不一致。规范化理论包括多个范式,从低到高依次为:
1.2.4.4.1 第一范式(1NF)
定义:关系中的每个属性都是原子的,不可再分解。
示例:
- 反例:将学生的联系信息存储为"电话,邮箱",可以分解为"电话"和"邮箱"两个属性
- 正例:每个属性都是不可再分的基本类型
1.2.4.4.2 第二范式(2NF)
定义:在第一范式的基础上,非主属性完全依赖于主键。
示例:
- 反例:在选课表中,课程名称依赖于课程ID,而不是主键(学生ID,课程ID)
- 正例:将课程名称移动到课程表中,选课表只存储学生ID和课程ID
1.2.4.4.3 第三范式(3NF)
定义:在第二范式的基础上,非主属性不传递依赖于主键。
示例:
- 反例:在学生表中,班主任依赖于班级ID,班级ID依赖于学生ID,存在传递依赖
- 正例:将班主任移动到班级表中,学生表只存储班级ID
1.2.4.4.4 更高范式
除了以上三个基本范式,还有BCNF(Boyce-Codd范式)、4NF、5NF等更高范式。在实际应用中,通常只需要满足前三个范式即可。
1.2.4.5 数据库设计的最佳实践
- 遵循规范化原则:减少数据冗余和不一致
- 合理选择数据类型:根据数据特点选择合适的数据类型
- 定义合适的约束:使用主键、外键、唯一性约束、检查约束等
- 设计良好的索引:为经常用于查询、排序和连接的列创建索引
- 考虑性能因素:对于大数据量的表,考虑分区、分表等策略
- 保持命名一致性:使用统一的命名规范,提高可读性
- 考虑扩展性:设计时考虑未来可能的需求变化
- 进行适当的反规范化:在某些情况下,为了提高性能,可以适当反规范化
1.2.5 SQL语言最佳实践
1.2.5.1 查询优化
- 只查询需要的列 :避免使用
SELECT *,只选择需要的列 - 使用WHERE子句限制结果集:减少返回的数据量
- 合理使用索引:为经常用于WHERE、ORDER BY、JOIN的列创建索引
- 避免在WHERE子句中使用函数:会导致索引失效
- 使用LIMIT限制结果数量:特别是在分页查询中
- 合理使用JOIN:避免不必要的JOIN操作
- 使用EXPLAIN分析查询计划:找出性能瓶颈
1.2.5.2 数据操作优化
- 使用批量插入:减少插入操作的次数
- 避免在循环中执行SQL:将多条SQL合并为一条
- 使用事务:确保数据一致性,减少日志写入
- 合理使用索引:插入、更新、删除操作会维护索引,索引过多会影响性能
- 定期清理无用数据:使用DELETE或TRUNCATE清理过期数据
1.2.5.3 安全性
- 使用参数化查询:避免SQL注入攻击
- 限制用户权限:遵循最小权限原则
- 使用加密存储敏感数据:如密码、身份证号等
- 定期备份数据:防止数据丢失
- 使用SSL连接:加密数据传输
1.2.6 实践项目:设计学生管理系统数据库
1.2.6.1 项目需求分析
设计一个简单的学生管理系统,包含以下功能:
- 学生信息管理
- 班级信息管理
- 课程信息管理
- 选课管理
- 成绩管理
1.2.6.2 概念设计
-
实体识别:
- 学生(Student)
- 班级(Class)
- 课程(Course)
- 成绩(Score)
-
ER模型:
- 学生与班级:多对一关系
- 学生与课程:多对多关系(通过成绩表关联)
- 课程与成绩:一对多关系
1.2.6.3 逻辑设计
-
班级表(classes):
- class_id:班级ID,主键
- class_name:班级名称,非空
- teacher_name:班主任名称
- create_time:创建时间
-
学生表(students):
- student_id:学生ID,主键
- student_name:学生姓名,非空
- gender:性别
- age:年龄,检查约束>0
- class_id:班级ID,外键
- create_time:创建时间
-
课程表(courses):
- course_id:课程ID,主键
- course_name:课程名称,非空
- credit:学分
- teacher_name:授课教师
- create_time:创建时间
-
成绩表(scores):
- score_id:成绩ID,主键
- student_id:学生ID,外键
- course_id:课程ID,外键
- score:成绩,检查约束0-100
- exam_time:考试时间
- create_time:创建时间
1.2.6.4 物理设计
-
创建数据库和表:
sql-- 创建数据库 CREATE DATABASE student_management; -- 连接到数据库 \c student_management; -- 创建班级表 CREATE TABLE classes ( class_id SERIAL PRIMARY KEY, class_name VARCHAR(50) NOT NULL, teacher_name VARCHAR(50), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 创建学生表 CREATE TABLE students ( student_id SERIAL PRIMARY KEY, student_name VARCHAR(50) NOT NULL, gender VARCHAR(10) CHECK (gender IN ('男', '女', '其他')), age INTEGER CHECK (age > 0), class_id INTEGER, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (class_id) REFERENCES classes(class_id) ); -- 创建课程表 CREATE TABLE courses ( course_id SERIAL PRIMARY KEY, course_name VARCHAR(50) NOT NULL, credit NUMERIC(3,1), teacher_name VARCHAR(50), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 创建成绩表 CREATE TABLE scores ( score_id SERIAL PRIMARY KEY, student_id INTEGER NOT NULL, course_id INTEGER NOT NULL, score NUMERIC(5,2) CHECK (score BETWEEN 0 AND 100), exam_time DATE, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (student_id) REFERENCES students(student_id), FOREIGN KEY (course_id) REFERENCES courses(course_id), UNIQUE (student_id, course_id) -- 确保每个学生每门课程只有一个成绩 ); -
创建索引:
sql-- 为经常用于查询的列创建索引 CREATE INDEX idx_students_class_id ON students(class_id); CREATE INDEX idx_scores_student_id ON scores(student_id); CREATE INDEX idx_scores_course_id ON scores(course_id); CREATE INDEX idx_scores_student_course ON scores(student_id, course_id); -
插入测试数据:
sql-- 插入班级数据 INSERT INTO classes (class_name, teacher_name) VALUES ('一班', '张老师'), ('二班', '李老师'), ('三班', '王老师'); -- 插入学生数据 INSERT INTO students (student_name, gender, age, class_id) VALUES ('张三', '男', 18, 1), ('李四', '女', 17, 1), ('王五', '男', 18, 2), ('赵六', '女', 17, 2), ('孙七', '男', 18, 3), ('周八', '女', 17, 3); -- 插入课程数据 INSERT INTO courses (course_name, credit, teacher_name) VALUES ('数学', 4.0, '张老师'), ('英语', 4.0, '李老师'), ('语文', 4.0, '王老师'), ('物理', 3.0, '赵老师'), ('化学', 3.0, '钱老师'); -- 插入成绩数据 INSERT INTO scores (student_id, course_id, score, exam_time) VALUES (1, 1, 85.5, '2025-01-15'), (1, 2, 90.0, '2025-01-16'), (1, 3, 80.5, '2025-01-17'), (2, 1, 95.0, '2025-01-15'), (2, 2, 85.5, '2025-01-16'), (2, 3, 90.0, '2025-01-17'), (3, 1, 80.0, '2025-01-15'), (3, 2, 75.5, '2025-01-16'), (3, 3, 85.0, '2025-01-17'), (4, 1, 70.5, '2025-01-15'), (4, 2, 80.0, '2025-01-16'), (4, 3, 75.5, '2025-01-17'); -
查询测试:
sql-- 查询每个学生的姓名、班级和班主任 SELECT s.student_name, c.class_name, c.teacher_name FROM students s INNER JOIN classes c ON s.class_id = c.class_id; -- 查询每个学生的每门课程成绩 SELECT s.student_name, c.course_name, sc.score FROM students s INNER JOIN scores sc ON s.student_id = sc.student_id INNER JOIN courses c ON sc.course_id = c.course_id ORDER BY s.student_name, c.course_name; -- 查询每个学生的平均成绩 SELECT s.student_name, AVG(sc.score) AS avg_score FROM students s INNER JOIN scores sc ON s.student_id = sc.student_id GROUP BY s.student_name ORDER BY avg_score DESC; -- 查询每门课程的平均成绩 SELECT c.course_name, AVG(sc.score) AS avg_score FROM courses c INNER JOIN scores sc ON c.course_id = sc.course_id GROUP BY c.course_name ORDER BY avg_score DESC;
1.2.7 关系型数据库对比
为了帮助你更全面地理解关系型数据库,本节将对比PostgreSQL 18、SQL Server 2019+和MySQL 8.0+在关系模型实现、SQL标准支持和核心特性方面的差异。
1.2.7.1 关系模型实现对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 关系模型遵循程度 | 严格遵循关系模型理论 | 严格遵循关系模型理论 | 部分遵循关系模型理论 |
| 数据组织方式 | 基于表的二维结构,支持复杂数据类型 | 基于表的二维结构,支持复杂数据类型 | 基于表的二维结构,支持复杂数据类型 |
| 主键支持 | 支持单字段和复合主键 | 支持单字段和复合主键 | 支持单字段和复合主键 |
| 外键支持 | 完整的外键约束支持 | 完整的外键约束支持 | 仅InnoDB存储引擎完整支持外键约束 |
| 视图支持 | 强大的视图支持,包括可更新视图、物化视图 | 完整的视图支持,包括可更新视图、索引视图 | 基本的视图支持,部分视图可更新 |
| 存储过程支持 | 完整的存储过程支持,支持多种语言 | 强大的存储过程支持,支持T-SQL | 基本的存储过程支持,支持MySQL存储过程语言 |
| 触发器支持 | 完整的触发器支持,支持多种触发时机 | 强大的触发器支持,包括DML和DDL触发器 | 基本的触发器支持,主要支持DML触发器 |
| 函数支持 | 支持自定义函数,支持多种语言 | 支持自定义函数,支持T-SQL | 支持自定义函数,支持MySQL函数语言 |
1.2.7.2 SQL标准支持对比
| 标准版本 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| SQL标准支持级别 | SQL:2016(高度兼容) | SQL:2016(良好兼容) | SQL:2011(部分兼容) |
| 基本SQL语法 | 完全支持SELECT/INSERT/UPDATE/DELETE | 完全支持SELECT/INSERT/UPDATE/DELETE | 完全支持SELECT/INSERT/UPDATE/DELETE |
| JOIN操作 | 支持INNER/LEFT/RIGHT/FULL/CROSS JOIN | 支持INNER/LEFT/RIGHT/FULL/CROSS JOIN | 支持INNER/LEFT/RIGHT/CROSS JOIN,有限支持FULL JOIN |
| 子查询支持 | 完整的子查询支持,包括嵌套子查询 | 完整的子查询支持 | 基本的子查询支持,部分复杂子查询可能有性能问题 |
| CTE支持 | 完整的CTE支持,包括递归CTE | 完整的CTE支持,包括递归CTE | 支持CTE,包括递归CTE(8.0+) |
| 窗口函数支持 | 完整的窗口函数支持,符合SQL标准 | 完整的窗口函数支持 | 基本的窗口函数支持(8.0+) |
| MERGE语句 | 支持MERGE语句(15+) | 强大的MERGE语句支持 | 支持INSERT ... ON DUPLICATE KEY UPDATE(类似MERGE) |
| JSON支持 | 强大的JSON/JSONB支持,包括JSONPath | 良好的JSON支持,包括JSONPath | 基本的JSON支持,包括JSONPath(8.0+) |
1.2.7.3 核心特性对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| ACID支持 | 完全支持ACID | 完全支持ACID | 仅InnoDB存储引擎完全支持ACID |
| 并发控制 | MVCC(多版本并发控制) | MVCC + 锁定机制 | MVCC(InnoDB存储引擎) |
| 事务隔离级别 | 读未提交、读已提交、可重复读、串行化 | 读未提交、读已提交、可重复读、快照隔离、串行化 | 读未提交、读已提交、可重复读(默认)、串行化 |
| 索引类型 | B-Tree、Hash、GiST、GIN、SP-GiST、BRIN | B-Tree、Hash、Columnstore、Spatial、XML | B-Tree(默认)、Hash、Full-Text、Spatial |
| 分区表支持 | 强大的分区表支持,包括范围、列表、哈希、复合分区 | 完整的分区表支持,包括范围、列表、哈希、列存储分区 | 基本的分区表支持,包括范围、列表、哈希分区 |
| 并行查询 | 强大的并行查询支持,支持多种操作 | 良好的并行查询支持 | 基本的并行查询支持(8.0+) |
| 全文搜索 | 强大的全文搜索支持 | 完整的全文搜索支持 | 基本的全文搜索支持 |
| 空间数据支持 | 强大的PostGIS扩展,GIS功能全面 | 内置空间数据类型和函数 | 有限的空间数据支持(需MySQL Spatial扩展) |
| 扩展性 | 强大的扩展机制,支持自定义类型、函数、扩展 | 有限的扩展性,主要通过扩展包 | 有限的扩展性,通过插件系统 |
1.2.7.4 适用场景对比
| 场景类型 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 复杂数据模型 | 非常适合,支持复杂数据类型和关系 | 非常适合,支持复杂数据模型 | 适合简单到中等复杂度的数据模型 |
| 高并发事务 | 适合,MVCC机制支持高并发 | 非常适合,企业级事务处理 | 适合,尤其是InnoDB存储引擎 |
| 数据分析 | 适合,支持复杂查询和分析 | 非常适合,尤其是与Microsoft BI工具集成 | 适合简单到中等复杂度的数据分析 |
| Web应用 | 适合,尤其是需要高级特性的Web应用 | 适合,尤其是.NET生态的Web应用 | 非常适合,尤其是LAMP/MEAN栈Web应用 |
| 企业应用 | 适合,尤其是需要高可靠性的企业应用 | 非常适合,大型企业应用的首选 | 适合中小型企业应用,成本敏感场景 |
| 开源项目 | 非常适合,开源免费,生态活跃 | 适合,有免费Express版本 | 非常适合,开源免费,广泛使用 |
1.2.8 总结
本章节介绍了关系型数据库的基础概念,包括:
- 数据库的基本概念和组成
- 关系模型的基本概念和特点
- SQL语言的分类和基本语法
- 数据库设计的步骤和原则
- 数据库规范化理论
- SQL语言的最佳实践
- 一个完整的学生管理系统数据库设计案例
- 与SQL Server 2019+和MySQL 8.0+的关系型数据库对比
通过本章节的学习,你应该已经掌握了关系型数据库的基本概念和设计方法,能够理解和使用SQL语言进行基本的数据操作。同时,通过与SQL Server 2019+和MySQL 8.0+的对比,你了解了不同关系型数据库在关系模型实现、SQL标准支持和核心特性方面的差异,这将有助于你在不同数据库间迁移和切换。
在接下来的章节中,我们将学习PostgreSQL 18的安装配置、高级SQL语法、数据库设计等内容,逐步深入PostgreSQL的世界。
1.2.9 思考与练习
1.2.9.1 思考问题
- 什么是关系型数据库?它的主要特点是什么?
- 关系模型的基本概念包括哪些?
- SQL语言分为哪几类?每类包括哪些主要命令?
- 数据库设计的步骤是什么?
- 什么是数据库规范化?主要包括哪些范式?
1.2.9.2 练习题
- 设计一个简单的博客系统数据库,包含用户、文章、评论等实体
- 编写SQL语句,查询每个班级的学生人数和平均年龄
- 编写SQL语句,查询成绩在80分以上的学生姓名和课程名称
- 什么是索引?索引的作用是什么?
- 数据库设计的最佳实践有哪些?
- 简述关系完整性约束的三种类型及其作用
- 什么是ER模型?它在数据库设计中的作用是什么?
- 简述第一范式、第二范式和第三范式的定义和要求
- 设计一个简单的电商系统数据库,包含商品、订单、用户等实体
- 编写SQL语句,查询每门课程的最高分、最低分和平均分