MySQL - 关系模型

关系模型本质上是若干个存储数据的二维表。

表的每一行称为 记录(Record),每一列称为 字段(Column)

字段定义了数据类型(整型、浮点型、字符串、日期等),以及是否允许为 NULL(表示字段数据不存在)。

关系数据库中,关系是通过 主键外键 来维护的。

RDBMS(关系数据库管理系统)的特点:

  1. 数据以表格形式出现
  2. 每行为一条记录
  3. 每列为字段名称对应的数据域(每列数据类型相同)
  4. 行和列组成表单(数据矩阵)
  5. 若干表单组成 database

主键

关系表中的每一条记录都包含若干字段。同一个表的所有记录都有相同的字段定义。

关系表的约束:表中任意两条记录不能重复。

不能重复不代表不存在两条完全相同的记录,而是指当两条记录不同时,要能通过某个字段 唯一区分出他们。

主键用来唯一定位记录,故而在记录插入表中之后,不能轻易修改。

选取主键的基本原则:不使用任何业务相关的字段作为主键(最大程度上避免主键修改的可能性),当然也不能是 NULL。

主键字段一般命名为 id,常见可作为 id 的字段类型:

  1. 自增整数类型:数据库会在插入数据时自动为每个记录分配一个自增整数。
  2. 全局 GUID 类型:使用一种全局唯一的字符串作为主键。类似8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID算法通过网卡MAC地址、时间戳和随机数保证任意计算机在任意时间生成的字符串都是不同的,大部分编程语言都内置了GUID算法,可以自己预算出主键。

对于大部分应用来说,通常自增类型的主键就能满足需求。

BIGINT 自增类型最多可以记录 922亿亿条记录。

联合主键

顾名思义,联合主键就是用多个字段来唯一标识记录,这些字段共同组成主键,就叫联合主键。

对于联合主键,允许有一列重复,只要不是所有主键列都重复即可。

说白了就是互相帮助。你不行了我上,但是不能都不行。

联合主键的存在会提高关系表的复杂度,所以不常用。

外键

从 一对多 引入

一个班级对应多个学生,是典型的 “一对多” 关系。即一个classes的记录可以对应多个students表的记录。

为了表达这种一对多的关系,我们需要在students表中加入一列class_id,让它的值与classes表的某条记录相对应。

这样,我们就可以根据class_id这个列直接定位出一个students表的记录应该对应到classes的哪条记录。

students表中,通过class_id的字段,可以把数据与另一张表关联起来,这种列称为 外键

外键在数据库中的两种表现形式:

  1. 名副其实的外键:

    定义了外键约束

    1
    2
    3
    4
    ALTER TABLE students
    ADD CONSTRAINT fk_class_id
    FOREIGN KEY (class_id)
    REFERENCES classes (id);
    • 外键约束的名称 fk_class_id 可以任意。
    • FOREIGN KEY (class_id) 指定了 class_id 作为外键。
    • REFERENCES classes (id) 指定了这个外键将关联到 classes 表的 id 列(即 classes 表的主键)。

    删除外键约束,通过 ALTER TABLE实现

    1
    2
    ALTER TABLE students
    DROP FOREIGN KEY fk_class_id;

    这里没有删除外键这一列,只是删除约束而已。删除列是通过DROP COLUMN ...实现的。

  2. 逻辑上的外键:

    外键约束会降低数据库的性能,所以为了追求速度,不设置外键约束,而仅靠应用程序自身来保证逻辑的正确性。

    这时 (1)中的 class_id 就只是普通的列,而只是在逻辑意义上起到了外键的作用而已。

多对多

多对多关系实例:一个老师对应多个班级,一个班级也可以对应多个老师。因此班级和老师之间存在多对多关系。

多对多关系是通过两个一对多关系实现的:有一个中间表,关联两个一对多关系。

一对一

一对一关系:一个表的记录对应到另一个表的唯一一个记录。

这样的表可以根据外键合并也可以拆分。

综上,关系数据库通过外键可以实现一对多,多对多和一对一的关系。外键既可以通过数据库来约束,也可以不设置约束,仅靠应用陈旭的逻辑实现。

索引

在关系数据库中存有多条记录,为了快速的找到某条记录,我们使用索引。

索引:关系数据库中对某一列或多个列的值进行预排序的数据结构。可在查找记录时直接定位到符合条件的记录,大大加快查询速度。

例如,对 students 表:

  • id 学号
  • class_id 班级
  • name 姓名
  • gender 性别
  • score 成绩

如果要经常根据score列进行查询,就可以对score列创建索引:

1
2
ALTER TABLE students
ADD INDEX idx_score (score);

使用ADD INDEX idx_score (score)就创建了一个名称为idx_score,使用列score的索引。

索引名称是任意的,索引如果有多列,可以在括号里依次写上,例如:

1
2
ALTER TABLE students
ADD INDEX idx_name_score (name, score);

索引的效率取决于索引列的值是否散列,对于主键,因为主键保证绝对唯一,所以使用主键索引效率最高。

关系数据库会自动对其创建主键索引。

虽然索引提高了查询效率,但是在插入、更新和删除记录使,需要同时修改索引。故而索引越多,插入等操作的速度就会更慢。

唯一索引

根据业务要求,具有唯一性约束的列(例如身份证号码)可以添加唯一索引,从而保证这一列的值具有唯一性。例如学生的身份证号不能重复:

1
2
ALTER TABLE students
ADD UNIQUE INDEX uni_pid (pid);

通过 unique 关键字添加唯一索引

也可以只添加唯一约束不创建唯一索引:

1
2
ALTER TABLE students
ADD CONSTRAINT uni_pid UNIQUE (pid);

添加索引只不过是让数据库的查询锦上添花,没有索引数据库当然也能正常运行,因此索引可以在使用数据库的过程中逐步优化。