【问题标题】:Which database scheme is better for performance aspect?哪种数据库方案在性能方面更好?
【发布时间】:2019-12-03 17:40:53
【问题描述】:

----方案1----

CREATE TABLE college (
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
address VARCHAR(250),
PRIMARY KEY (id)
);

CREATE TABLE student (
college INT NOT NULL,
username VARCHAR(50) NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
CONSTRAINT pk PRIMARY KEY (college,username)
);

CREATE TABLE subject (
college INT NOT NULL,
id INT NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
CONSTRAINT pk PRIMARY KEY (college,id)
);

CREATE TABLE marks (
college INT NOT NULL,
student VARCHAR(50) NOT NULL,
subject INT NOT NULL,
marks INT NOT NULL,
// forget about standard for this example
FOREIGN KEY (college) REFERENCES college(id),
FOREIGN KEY (student) REFERENCES student(username),
FOREIGN KEY (subject) REFERENCES subject(id),
CONSTRAINT pk PRIMARY KEY (college,subject,student)
);

----方案2----

CREATE TABLE college (
id INT AUTO_INCREMENT,
name VARCHAR(250) NOT NULL,
address VARCHAR(250),
PRIMARY KEY (id)
);


CREATE TABLE student (
college INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
PRIMARY KEY (id)
);

CREATE TABLE subject (
college INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(100),
FOREIGN KEY (college) REFERENCES college(id),
PRIMARY KEY (id)
);

CREATE TABLE marks (
student VARCHAR(50) NOT NULL,
subject INT NOT NULL,
id BIGINT NOT NULL AUTO_INCREMENT,
marks INT NOT NULL,
// forget about standard for this example
FOREIGN KEY (student) REFERENCES student(id),
FOREIGN KEY (subject) REFERENCES subject(id),
PRIMARY KEY (id)
);

看看上面的数据库方案,看起来 Scheme1 在搜索特定学生的结果时会提供更好的性能,并且在过滤结果时会更快,但感觉并不是所有的规范化形式。而另一方面,Scheme2 看起来完全正常,但可能需要更多的 JOIN 操作来获取某些结果或过滤数据。

如果我在这里的方案有误,请告诉我,同时告诉我哪个更好?

【问题讨论】:

  • 恕我直言,坚持同一所大学的两个不同学生可能不具有相同的名字是错误的。有时人们确实有相同的名字。
  • @O.Jones 这是username - 不是name。或者我错过了什么?
  • 您认为第一个模式中违反了哪些规范化规则?
  • 在不知道将应用哪些查询的情况下无法判断架构。

标签: mysql sql database database-design query-optimization


【解决方案1】:

我会选择 Schema 2:在引用表时,使用单个列(Schema 1 中的 auto_incremented 主键)比使用列组合(Schema 1 中的复合主键)更容易完成。此外,正如 O.Jones 所评论的,模式 2 假设同一所大学的两个学生不能有相同的名字,这似乎不明智。

Schema 1 还存在其他问题,例如,将分数与学生相关联的外键格式不正确(您需要一个包含大学 id 而不仅仅是学生姓名的复合外键)。

使用正确定义的外键引用主键,性能不会成为问题;联接在这种情况下表现良好。

但是 Schema 2 中应该修复一个缺陷,即在标记表中存储对学院的引用。你不需要这个,因为一个学生属于一个学院(学生表中有一个对学院的引用)。

另外,我不确定一门学科是否应该属于一所大学:同一学科不可能在不同的大学教授吗?

最后,我建议为外键列提供更清晰的名称,例如用student_id 代替student,用college_id 代替college

【讨论】:

    【解决方案2】:

    如果不首先了解实体之间的关系,就很难评估架构是否已规范化。一个学生可以只与一所大学相关联吗?一个学生是否可以多次与同一学科相关联,获得不同的分数?

    声明外键可保持参照完整性,但会减慢插入和更新速度。您可以在不声明 fks 的情况下获得相同的功能,但最终可能会得到一些孤立的记录。特定索引是否用于 fk 对 SELECT 查询性能没有影响。

    JOIN 操作使用索引。 fks也一样。因此,如果您有正确的索引,您的 JOIN 操作将是高效的。但是如果不知道您的 JOIN 查询,就不可能知道哪些索引是最好的。

    按照惯例,每个表的 id 列在前。许多设计者在它出现的表格之后命名每个id列,例如college.college_id而不是college.id。这使得 JOIN 查询更易于阅读。

    您应该在 student 表 (student.student_id) 中使用代理主键,而不是使用学生姓名作为主键的一部分。加入id 值比加入VARCHAR() 值更快。而且,有些学生可能会分享名字。 (在现实世界中,人们的出生日期与他们的名字一起出现在表格中:这有助于区分人们。)

    我认为您的marks 表应该包含这些列:

    CREATE TABLE marks (
      student_id INT NOT NULL,
      subject_id INT NOT NULL,
      marks INT NOT NULL,
      // foreign keys as needed
      PRIMARY KEY (student_id, subject_id)
    );
    

    一个学生可以在同一科目获得多个分数吗?在这种情况下,使用 marks_id 作为 pk 而不是 (student_id, subject_id)

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 2012-09-28
      • 1970-01-01
      • 2011-09-30
      • 1970-01-01
      • 2023-03-21
      • 2010-09-23
      • 1970-01-01
      相关资源
      最近更新 更多