哪种数据库方案在性能方面更好?

时间:2019-12-03 17:40:53

标签: mysql database performance database-design database-normalization

----方案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操作才能获取某些结果或过滤数据。

请告诉我我是否对我的计划有误,还请告诉我哪个更好?

2 个答案:

答案 0 :(得分:3)

我会选择模式2:当涉及到引用表时,使用单列(模式1中的auto_incremented主键)要比组合列(模式1中的键主键)更容易。另外,正如O.Jones所评论的那样,模式2假设同一所大学中的两个学生不能使用相同的名字,这似乎不明智。

模式1还存在其他问题,例如,将标记与学生联系起来的外键格式不正确(您需要一个包含大学ID而不是学生姓名的通用外键)。

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

但是在模式2中应该修复一个缺陷,那就是将对大学的引用存储在标记表中。您不需要这样做,因为学生属于一所大学(“学生表”中有对该大学的引用)。

此外,我不确定某个科目应属于一所大学:难道同一科目是否会在不同的大学教授?

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

答案 1 :(得分: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)

相关问题