未记录事实核验 · 状态:维护中

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用边界与维护说明

本文适合已有基础SQL知识的读者学习关系模型、完整性约束、关系代数及规范化,并参考电商表结构与索引设计,不是完整可执行练习或可部署项目。各节SQL应作为独立示例阅读:同名表存在不同定义,查询所需的students.age、students.major、courses.is_required及graduated_students、categories、brands表结构未完整提供。代码主要采用MySQL风格,CHECK的执行受版本和表达式限制;保留的CURDATE()及子查询CHECK不能直接用于该实现,经理工资表达式也未实现注释所述业务规则,不能作为有效约束照搬。条件索引已明确属于其他数据库方言,JOIN写法本身不代表性能提升。本次仅作全文结构与内容一致性审阅,未进行数据库执行测试、外部事实核验或链接可达性检查。

关系型数据库理论基础 - 关系模型与数据组织原理

tip 学习目标

本文将深入介绍关系型数据库的理论基础,包括关系模型的数学原理、数据完整性约束机制以及关系运算理论。

核心内容:

  • 关系模型的数学理论基础
  • 数据完整性约束的技术实现
  • 关系代数基本运算及SQL示例
  • 范式理论与数据库设计规范

学习价值:理解关系型数据库的理论基础,为高质量的数据库设计和优化奠定坚实基础。

abstract 本节概览

  • 学习目标:掌握关系模型的理论基础和技术实现
  • 技能价值:具备数据库设计和优化的理论指导能力
  • 预计用时:25分钟
  • 学习成果:能够基于关系理论进行数据库设计
  • 应用前景:为数据库架构设计提供理论支撑

关系模型理论基础

关系模型的数学定义

关系(Relation):在数学上,关系是笛卡尔积的有限子集。在数据库中,关系对应于表(Table)。

元组(Tuple):关系中的一行数据,对应表中的记录。

属性(Attribute):关系中的列名,定义数据的特征。

域(Domain):属性的取值范围,如整数域、字符串域等。

度(Degree):关系中属性的个数。

基数(Cardinality):关系中元组的个数。

关系模型的基本概念

关系模式(Relation Schema)

-- 关系模式定义示例
Students(StudentID, Name, Age, Major, EnrollYear)
-- 其中:StudentID为主键,Age属于整数域,Major属于字符串域

关系实例(Relation Instance)

-- 关系实例(表中的实际数据)
+----------+--------+-----+----------+----------+
| StudentID| Name   | Age | Major    | EnrollYear|
+----------+--------+-----+----------+----------+
| 001      | 张三   | 20  | 计算机   | 2023     |
| 002      | 李四   | 21  | 数学     | 2022     |
| 003      | 王五   | 19  | 物理     | 2024     |
+----------+--------+-----+----------+----------+

超键(Super Key):能够唯一标识关系中每个元组的属性集合。

候选键(Candidate Key):最小的超键,不能再去掉任何属性。

主键(Primary Key):从候选键中选择的一个作为主要标识。

外键(Foreign Key):用于引用另一关系或同一关系中候选键的属性或属性集合;SQL中通常引用主键或满足相应条件的唯一键。

数据完整性约束机制

实体完整性约束

定义:主键约束,确保关系中每个元组都有唯一标识。

技术实现:

-- 主键约束实现
CREATE TABLE students (
    student_id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 复合主键示例
CREATE TABLE enrollments (
    student_id INT,
    course_id INT,
    enrollment_date DATE,
    PRIMARY KEY (student_id, course_id, enrollment_date)
);

约束规则:

  • 主键属性不能为空(NOT NULL)
  • 主键值在关系中必须唯一
  • 一个关系只能有一个主键

参照完整性约束

定义:外键约束,确保关系间引用的一致性。

技术实现:

-- 外键约束实现
CREATE TABLE courses (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(100) NOT NULL,
    credits INT CHECK (credits > 0)
);

CREATE TABLE student_courses (
    enrollment_id INT PRIMARY KEY AUTO_INCREMENT,
    student_id INT,
    course_id INT,
    grade DECIMAL(3,1),
    
    -- 定义外键约束
    FOREIGN KEY (student_id) REFERENCES students(student_id)
        ON DELETE CASCADE
        ON UPDATE CASCADE,
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
        ON DELETE RESTRICT
        ON UPDATE CASCADE
);

约束操作:

  • CASCADE:级联删除/更新
  • RESTRICT:限制删除/更新
  • SET NULL:设置为空值
  • SET DEFAULT:设置为默认值;是否支持取决于数据库实现,前述MySQL常用的InnoDB外键不支持该操作

域完整性约束

定义:确保属性值符合预定义的数据类型和约束条件。

MySQL执行边界:MySQL从8.0.16起才实际执行CHECK约束;更早版本可能接受语法但不执行。以下含CURDATE()的CHECK不符合MySQL的表达式限制,不能直接执行,且不能仅将当前日期替换为固定日期来实现持续有效的业务规则。

技术实现:

-- 域完整性约束示例
CREATE TABLE products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) CHECK (price > 0),
    category ENUM('electronics', 'books', 'clothing', 'food'),
    stock_quantity INT DEFAULT 0 CHECK (stock_quantity >= 0),
    manufacturing_date DATE CHECK (manufacturing_date <= CURDATE()),
    
    -- 复杂约束条件
    CONSTRAINT price_range CHECK (
        (category = 'electronics' AND price >= 10.00) OR
        (category != 'electronics' AND price >= 1.00)
    )
);

用户自定义完整性约束

业务规则约束:

-- 业务规则约束示例
CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    hire_date DATE NOT NULL,
    salary DECIMAL(10,2) CHECK (salary > 0),
    department VARCHAR(30),
    manager_id INT,
    
    -- 自引用外键约束
    FOREIGN KEY (manager_id) REFERENCES employees(employee_id),
    
    -- 业务规则:员工不能管理自己
    CONSTRAINT no_self_management CHECK (employee_id != manager_id),
    
    -- 业务规则:经理的工资必须高于普通员工
    CONSTRAINT manager_salary_rule CHECK (
        manager_id IS NULL OR 
        salary > (SELECT AVG(salary) FROM employees WHERE manager_id = employee_id)
    )
);

关系代数及SQL示例

基本关系运算

选择(Selection, σ):

-- 选择运算:σ(age > 20)(Students)
SELECT * FROM students WHERE age > 20;

投影(Projection, π):

-- 投影运算:π(name, major)(Students)
SELECT DISTINCT name, major FROM students;

并(Union, ∪):

-- 并运算:CS_Students ∪ Math_Students
SELECT student_id, name FROM students WHERE major = 'Computer Science'
UNION
SELECT student_id, name FROM students WHERE major = 'Mathematics';

差(Difference, −):

-- 差运算:All_Students − Graduated_Students
SELECT s.student_id, s.name FROM students s
WHERE NOT EXISTS (
    SELECT 1 FROM graduated_students g
    WHERE g.student_id = s.student_id
);

笛卡尔积(Cartesian Product, ×):

-- 笛卡尔积:Students × Courses
SELECT s.*, c.*
FROM students s
CROSS JOIN courses c;

扩展关系运算

连接(Join, ⋈):

-- 内连接(θ-连接)
SELECT s.name, sc.grade, c.course_name
FROM students s
INNER JOIN student_courses sc ON s.student_id = sc.student_id
INNER JOIN courses c ON sc.course_id = c.course_id
WHERE sc.grade >= 90;

-- 左外连接
SELECT s.name, COALESCE(sc.grade, 'Not Enrolled') as grade
FROM students s
LEFT JOIN student_courses sc ON s.student_id = sc.student_id;

-- 自连接示例
SELECT e1.name as employee, e2.name as manager
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.employee_id;

除(Division, ÷):

-- 除运算示例:找出选修了所有必修课程的学生
SELECT s.student_id, s.name
FROM students s
WHERE NOT EXISTS (
    SELECT c.course_id
    FROM courses c
    WHERE c.is_required = TRUE
    AND NOT EXISTS (
        SELECT 1
        FROM student_courses sc
        WHERE sc.student_id = s.student_id
          AND sc.course_id = c.course_id
    )
);

范式理论与数据库设计

第一范式(1NF)

定义:关系中每个属性都是原子的,不可再分。

违反1NF的示例:

-- 违反1NF:interests字段包含多个值
+----------+--------+------------------------+
| StudentID| Name   | Interests              |
+----------+--------+------------------------+
| 001      | 张三   | 编程,音乐,体育         |
+----------+--------+------------------------+

符合1NF的设计:

-- 符合1NF的设计
CREATE TABLE students (
    student_id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
);

CREATE TABLE student_interests (
    student_id INT,
    interest VARCHAR(50),
    PRIMARY KEY (student_id, interest),
    FOREIGN KEY (student_id) REFERENCES students(student_id)
);

第二范式(2NF)

定义:满足1NF,且每个非主属性都完全函数依赖于每个候选键,不存在对候选键真子集的部分函数依赖;非主属性是指不属于任何候选键的属性。

违反2NF的示例:

-- 违反2NF:course_name仅依赖于course_id,不依赖于完整主键
CREATE TABLE enrollments_bad (
    student_id INT,
    course_id INT,
    course_name VARCHAR(100),  -- 部分依赖
    grade DECIMAL(3,1),
    PRIMARY KEY (student_id, course_id)
);

符合2NF的设计:

-- 拆分为两个表,消除部分依赖
CREATE TABLE courses (
    course_id INT PRIMARY KEY,
    course_name VARCHAR(100) NOT NULL
);

CREATE TABLE enrollments (
    student_id INT,
    course_id INT,
    grade DECIMAL(3,1),
    PRIMARY KEY (student_id, course_id),
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);

第三范式(3NF)

定义:对于每个非平凡函数依赖X → A,X是超键,或A是主属性(属于至少一个候选键);3NF也满足2NF。

违反3NF的示例:

-- 违反3NF:department_location传递依赖于student_id
CREATE TABLE students_bad (
    student_id INT PRIMARY KEY,
    name VARCHAR(50),
    department VARCHAR(50),
    department_location VARCHAR(100)  -- 传递依赖
);

符合3NF的设计:

-- 消除传递依赖
CREATE TABLE departments (
    department_id INT PRIMARY KEY,
    department_name VARCHAR(50),
    location VARCHAR(100)
);

CREATE TABLE students (
    student_id INT PRIMARY KEY,
    name VARCHAR(50),
    department_id INT,
    FOREIGN KEY (department_id) REFERENCES departments(department_id)
);

巴斯-科德范式(BCNF)

定义:对于每个非平凡函数依赖X → Y,决定因素X都必须是超键。BCNF比3NF更严格。

BCNF设计示例:

-- BCNF设计:处理多个候选键的情况
CREATE TABLE course_instructors (
    instructor_id INT,
    course_code VARCHAR(10),
    semester VARCHAR(20),
    room_number VARCHAR(10),
    
    -- 约束条件:
    -- (instructor_id, semester) → room_number
    -- (course_code, semester) → instructor_id
    -- (room_number, semester) → instructor_id
    
    PRIMARY KEY (course_code, semester),
    UNIQUE KEY (instructor_id, semester),
    UNIQUE KEY (room_number, semester)
);

企业级应用实践

电商系统数据库设计

-- 用户表设计
CREATE TABLE users (
    user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    phone VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
    
    INDEX idx_email (email),
    INDEX idx_phone (phone),
    INDEX idx_created_at (created_at)
);

-- 商品表设计
CREATE TABLE products (
    product_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    sku VARCHAR(50) UNIQUE NOT NULL,
    product_name VARCHAR(200) NOT NULL,
    description TEXT,
    category_id INT NOT NULL,
    brand_id INT,
    price DECIMAL(10,2) NOT NULL CHECK (price >= 0),
    cost DECIMAL(10,2) CHECK (cost >= 0),
    stock_quantity INT DEFAULT 0 CHECK (stock_quantity >= 0),
    weight DECIMAL(8,3) CHECK (weight > 0),
    status ENUM('active', 'inactive', 'discontinued') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    FOREIGN KEY (category_id) REFERENCES categories(category_id),
    FOREIGN KEY (brand_id) REFERENCES brands(brand_id),
    
    INDEX idx_sku (sku),
    INDEX idx_category (category_id),
    INDEX idx_price (price),
    INDEX idx_status_created (status, created_at)
);

-- 订单表设计
CREATE TABLE orders (
    order_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    order_number VARCHAR(32) UNIQUE NOT NULL,
    user_id BIGINT NOT NULL,
    order_status ENUM('pending', 'paid', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
    total_amount DECIMAL(12,2) NOT NULL CHECK (total_amount >= 0),
    shipping_fee DECIMAL(8,2) DEFAULT 0.00 CHECK (shipping_fee >= 0),
    tax_amount DECIMAL(10,2) DEFAULT 0.00 CHECK (tax_amount >= 0),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE RESTRICT,
    
    INDEX idx_user_id (user_id),
    INDEX idx_order_status (order_status),
    INDEX idx_created_at (created_at)
);

性能优化策略

索引设计策略:

-- 复合索引设计
CREATE INDEX idx_product_category_price ON products(category_id, price, status);
CREATE INDEX idx_order_user_status_date ON orders(user_id, order_status, created_at);

-- 覆盖索引设计
CREATE INDEX idx_product_list_cover ON products(category_id, status, product_id, product_name, price);

-- 部分索引(条件索引):以下为PostgreSQL等支持该语法的数据库示例,不能直接用于前述MySQL风格建表。
CREATE INDEX idx_active_products ON products(category_id, price) WHERE status = 'active';

查询优化实践:

-- 写法一:使用逗号连接;不能仅凭这种写法判断查询效率
SELECT p.product_name, p.price, c.category_name
FROM products p, categories c
WHERE p.category_id = c.category_id
AND p.price > 100
AND p.status = 'active';

-- 写法二:使用显式JOIN表达连接关系;性能需结合实际索引、数据分布和执行计划判断
SELECT p.product_name, p.price, c.category_name
FROM products p
INNER JOIN categories c ON p.category_id = c.category_id
WHERE p.status = 'active'
AND p.price > 100;

知识连接

学习检验

理论掌握检验:

  • [ ] 能够准确定义关系、元组、属性等基本概念
  • [ ] 理解主键、外键、候选键的区别和作用
  • [ ] 掌握数据完整性约束的分类和实现方法
  • [ ] 了解关系代数基本运算的含义和SQL实现

实践能力检验:

  • [ ] 能够设计符合范式要求的关系模式
  • [ ] 掌握完整性约束的SQL实现语法
  • [ ] 能够识别和解决数据冗余和异常问题
  • [ ] 具备复杂查询的关系代数分析能力

总结要点

关系模型理论:

  • 关系模型建立在严格的数学基础上,提供了数据组织的理论框架
  • 关系模型提供结构化的数据组织方式;数据一致性和完整性还依赖正确的约束、事务机制及业务实现
  • 关系代数为查询语言提供了理论基础

数据完整性:

  • 实体完整性确保每个记录的唯一性
  • 参照完整性维护表间关系的一致性
  • 域完整性保证数据值的有效性
  • 用户自定义约束实现业务规则的强制执行

范式理论应用:

  • 规范化可减少由函数依赖引起的数据冗余及更新异常,具体效果取决于依赖识别和关系分解是否正确
  • 不同范式适用于不同的业务场景
  • 实际设计中需要平衡范式要求与查询性能

#SQL #关系型数据库 #关系模型 #数据完整性 #范式理论

学习路径: