📜  功能依赖和属性闭包(1)

📅  最后修改于: 2023-12-03 15:36:58.292000             🧑  作者: Mango

功能依赖和属性闭包

什么是功能依赖?

在关系型数据库中,属性之间的关系有许多种,其中最重要的一种是 功能依赖(Functional Dependency,FD)。所谓功能依赖,就是指在一个关系中,一个或一组属性的取值决定了另一组属性的取值。

举个例子,我们有一个学生信息表,其中包含学生的学号、姓名、性别和年龄 four 个属性,那么我们可以说:

  • 学号决定一个人的姓名、性别和年龄;
  • 姓名不会决定其他人的性别和年龄;
  • 性别决定一个人的年龄;
  • 年龄不能决定其他属性。

因此,我们可以得出以下几个功能依赖:

{ 学号 } → { 姓名, 性别, 年龄 }
{ 姓名 } → { }
{ 性别 } → { 年龄 }
{ 年龄 } → { }
什么是属性闭包?

在上面的例子中,我们已经确定了每个属性决定的其他属性,但是我们还会遇到这样的情况:一些属性决定的属性还能再次决定其他属性。例如,在学生信息表中,我们再加入一个“系别”属性。因为系别与学号有关,所以系别也依赖于学号。而因为系别与年级的关系很密切,所以年级也依赖于学号。这个过程再继续下去,我们可能会发现,学号决定的属性以及这些属性再决定的属性就构成了一个封闭的集合。

这个封闭的集合就称为 属性闭包(Attribute Closure)。在关系中,我们经常要确定某一组属性的闭包,以便更好地维护数据的一致性和完整性。

怎样求属性闭包?

求属性闭包的过程很简单,我们只需要不断地判断出每个属性依赖的其他属性,再把这些属性加入到一个集合中,直到集合不再增大为止。

示例代码:

def closure(X, F):
    """
    计算X的闭包
    X: 元组,表示一组属性
    F: 元组,表示一组FD
    """
    # 初始化闭包为X
    ret = set(X)
    flag = True
    # 如果闭包仍在增大,则重复以下步骤
    while flag:
        flag = False
        for f in F:
            # 当前属性集合是某个FD的子集,则扩展闭包
            if set(f[0]).issubset(ret) and not set(f[1]).issubset(ret):
                ret |= set(f[1])
                flag = True
    return ret

示例代码:

# 给定一组FD和一个属性集合S,返回S的闭包
F = [(('A',), ('B', 'C')), (('B', 'C'), ('D',))]
S = ('A',)
closure(S, F)  # 输出 {A, B, C, D}

这个示例计算了属性集合 { A } 的闭包,结果为 { A, B, C, D }。

总结

在关系型数据库中,功能依赖和属性闭包是非常重要的概念。通过正确地计算功能依赖和属性闭包,我们可以更好地管理关系中的数据,确保数据的一致性和完整性。此外,还可以根据功能依赖进行关系的分解,有效地减少数据冗余和增强数据库的性能。