1

我现在正在玩数据库的想法。它可能不会以任何方式部署,更多的是一种学习体验。

它旨在简化我就读的大学中大量课程的导师信息的收集和处理。我在一个办公室兼职,该办公室每学期为几节课安排辅导员。

我有很多问题,但目前给我带来问题的一个问题是我如何存储每个导师的可用性。我目前正在考虑 3 个选项,并且我正在从技术角度寻找关于每个选项的优缺点的反馈。

背景: 导师信息存储在“导师”表中(导师ID引用此),必须能够调用以前的可用性。导师的可用性是离散的(每小时),并且在整个学期中保持不变。

选项1:

Table: Availability
+-----------+---------+-------+-------+---+---+---+----+---+
| avID (PK) | tutorID | year  |  sem  | M | T | W | Th | F |
|           |         | (int) | (int) |    (all strings)   |
+-----------+---------+-------+-------+---+---+---+----+---+

在此表中,可用性存储在一个字符串中(08、09、10、13、14 代表上午 8 点、上午 9 点、上午 10 点、下午 1 点和下午 2 点)。

数据可以被回收

SELECT * FROM Availability WHERE tutorID=0001 AND year=2013 AND sem=1

看看谁有空

SELECT * FROM Availability WHERE AND year=2013 AND sem=1 AND M LIKE '%08%'

选项 2:

Table: Availability
+-----------+---------+-------+-------+--------------+
| avID (PK) | tutorID | year  |  sem  | availability |
|           |         | (int) | (int) |     (set)    |
+-----------+---------+-------+-------+--------------+

在此布局中,可用性列作为 SET 数据类型存储在 mysql 中,选项是周一到周五的每个组合以及从 8 到 4 的每个时间(M08、M09...Th14、F16 等)。这可以得出 45 个可接受的值。这是我目前倾向于的一种,但我对 SET 数据类型了解不多。

数据可以被回收

SELECT * FROM Availability WHERE tutorID=0001 AND year=2013 AND sem=1

看看谁有空

SELECT * FROM Availability WHERE AND year=2013 AND sem=1 
                AND FIND_IN_SET('M09',availability) > 0

选项 3:

Table: Availability
+-----------+---------+-------+-------+-------+-------+
| avID (PK) | tutorID | year  |  sem  |  day  | time  |
|           |         | (int) | (int) | (int) | (int) |
+-----------+---------+-------+-------+-------+-------+

在此选项中,每个导师每年和每个时间段都有一行。

数据可以被回收

SELECT * FROM Availability WHERE year=2013 AND sem=2 AND tutorID=0001

可用性与

SELECT * FROM Availability WHERE year=2013 AND sem=2 AND day=3 AND time=14

无论如何...感谢您阅读所有这些内容。希望有人能够对此有所了解。我认为它基本上可以归结为最佳实践类型的问题。除非有什么我完全错过了!!

4

1 回答 1

3

您列出的所有选项均未标准化。基本上规范化,也是关系数据库技术的要点和好处之一,是避免存储冗余信息。

选项1

您不清楚要求,但我假设导师每天可能有超过一小时的时间。这会使选项 1 变得尴尬或不合适,因为您必须在一天内使用多行来涵盖多个会话。其他列的值将跨行重复——这种重复意味着违反规范化。

此外,选择文本作为开始时间的数据类型可能不是最佳选择。如果会话总是在小时开始,那么您正在处理小时数。如果处理数字,请将它们存储为数字(作为一般规则)。如果会话可能并不总是在小时开始,那么您正在处理时间值。相同的一般规则,将它们存储为时间数据类型。

选择 int 作为年份的数据类型可能不清楚。通常一个学年类似于“2013-2014”。

选项 2

在选项 2 中,将多个数据点填充到单个字段中绝对不是标准化的。虽然您的查询可以工作,但它至少有两个缺点。一是性能;通常搜索这样的多值字段会相对较慢。但更重要的是,违反规范化几乎总是会导致自己陷入困境。如果您想将附加值绑定到每个时隙怎么办 - 您不能因为当它们被粉碎在一起时您无法访问每个时隙。

选项 3

在选项 3 中,您越来越接近标准化设计。但是请注意多个字段将如何一起重复(yearsem)?同样,这种重复是违反规范化的标志。

概括

在设计时,通常拓宽或概括您的想法是一个好习惯。例如,会话总是会在整点开始并持续一小时吗?不见得。因此,使用时间值而不是小时数可能更明智。另一个例子,“学期”——并非所有学校都使用学期,甚至那些(你的)使用学期的学校也可能会改变。因此,概括为“学期”而不是做出与学期相关的假设可能是明智的。另一方面,不要过度概括,否则您可能会陷入毫无意义的设计混乱或陷入分析瘫痪。

标准化

为了规范化,寻找“事物”,可能采取行动的事物,或“拥有”其他事物的事物。我们称这些实体。

您已经将 标识tutor为一个单独的实体。好的。

我看到另一个:(term学期)。'year' 和 'sem' 的重复是线索。通过将这些值移动到另一个表中可以避免这种重复。该表用于“术语”实体。单独表格正确的另一个线索是我们可能希望将其他信息与“术语”表联系起来,例如术语的开始日期和长度(或停止日期)。这些额外的数据当然不应该在我们所有的“可用性”行中重复。term此类数据应在表的单行中存储一次。

我的设计

所以我最初的设计看起来像这张图。 多对多关系、Tutor、Availability 和 Term 三个表的关系图

This relationship is Many-to-Many. Each tutor may be available in multiple terms, and each term may have multiple tutors. A many-to-many is a problem in a relational design, and is always resolved with a third "bridge" or "junction" table. Many-to-many and bridge tables are quite common in databases designed for business contexts.

Here, the bridge table between them, is availibility_. That bridge table is a child table to both, and carries each parent's primary key (a foreign key). Tip: when I place parents (blue here) higher vertically than children (orange here), and I notice the "bird body with raised wings" pattern of a parent on either side, then I recognize a many-to-many relationship exists between the parents.


顺便说一句,有时会违反规范化。我们称之为“去规范化”。通常目标与性能有关。但是,只有在您咨询过另一位经验丰富的数据库设计人员之后才能进行非规范化,并且当您有充分的理由时,清楚地知道您要付出的代价,并彻底记录违规行为以供以后可能取代您的人的启发。

于 2013-11-05T08:48:18.540 回答