Normalization

Features of Good Relational Design

Decomposition

The only way to avoid the repitition-of-information problem is to decompose schemas. Not all decompositions are good. If we decompose a schema into two, we can lose information. This is known as lossy decomposition.

Image

Lossless Decomposition

We say that the decomposition is a lossless decomposition if there is no loss of information by replacing a schema with two relation schemas.

Normalization Theory

  • Decide whether a particular relation RR is in "good" form.
  • In the case that a relation RR is not in "good" form, decompose it into set of relations (R1,R2,...,RnR_1, R_2, ..., R_n) such that
    • each relation is in good form
    • the decomposition is a lossless composition
  • Our theory is based on:
    • Functional Dependencies
    • Multivalued Dependencies

Functional Dependencies

There are usually a variety of constraints (rules) on the data in the real world.

  • For example, some of the constraints that are expected to hold in a university database are:
  • Students and instructors are uniquely identified by their ID.
  • Each student and instructor has only one name.
  • Each instructor and student is (primarily) associated with only one department.
  • Each department has only one value for its budget, and only one associated building.

An instance of a relation that satisfies all such real-world constraints is called a legal instance of the relation. A legal instance of a database is one where all the relation instances are legal instances.

  • A superkey is a set of attributes that uniquely identifies an entire tuple
  • A functional dependency requires that the value for a certain set of attributes determines uniquely the value for another set of attributes.
  • A functional dependency is a generalization of the notion of a key.

Definition

Let RR be a relation schema αR\alpha \subseteq R and βR\beta \subseteq R. The functional dependency αβ\alpha \to \beta hold on RR iff and only if for any legal relations r(R)r(R), whenever any two tuples t1andt2t_1 and t_2 of rr agree on the attributes α\alpha, they also agree on the attributes β\beta.

Closure of a Set of Functional Dependencies

  • Given a set FF of functional dependencies, there are certain other functinoal dependencies that are logically implied by FF. The set of all functional dependencies logically implied by FF is the closure of FF. We denote the closure of FF by F+F+.

Keys and Functional Dependencies

KK is a superkey for relation schema RR if and only if KRK \to R and for no αK,αR\alpha \subset K, \alpha \to R.

Functional dependencies allow us to express constraints that cannot be expressed using superkeys.

Use of Functional Dependencies

We use functional dependencies to:

  • To test relations to see if they are legal under a given set of functional dependencies.
    • if a relation rr is legal under a set FF of functional dependencies, we say that rr satisfies FF
  • to specify constraints on the set of legal relations
    • we say that FF holds on RR if all legal relations on RR satisfy the set of functional dependencies

A functional dependency is trivial if it is satisfied by all instances of a relation. In general αβ\alpha \to \beta is trivial if βα\beta \subseteq \alpha.

Dependency Preservation

  • Testing functional dependency constraints each time the database is updated can be costly
  • It is useful to design the database in a way that constraints can be tested efficiently
  • If testing a functional dependency can be done by considering just one relation, then the cost of testing this constraint is low
  • When decomposing a relation it is possible that it is no longer possible to do the testing without having the perform a Cartesian Product
  • A decomposition that makes it computationally hard to enforce functional dependency is said to be NOT dependency preserving.

Let FiF_i be the set of dependencies in F+F+ that include only attributes in RiR_i

  • A decomposition is dependency preserving if (F1UF2U...UFn)+=F+(F_1 U F_2 U ... U F_n)+ = F+

With the above definition, testing for dependency preservation takes exponential time.

Normal Forms

Boyce-Codd Normal Form

  • A relation schema RR is in BCNF with respect to a set FF of functional dependencies if for all functional dependencies in F+F+ of the form αβ\alpha \to \beta where αR\alpha \subseteq R and βR\beta \subseteq R, at least one of the following holds:
  • αβ\alpha \to \beta is trivial
  • α\alpha is a superkey for RR

Decomposing a Schema into BCNF

Let RR be a schema RR that is not in BCNF. Let αβ\alpha \to \beta be the FD that causes a violation of BCNF.

We decompose RR into:

  • (\alpha \cup \beta)
  • (RR - (\beta - \alpha))

BCNF Decomposition Algorithm

result = {R}
done = False
compute F+
while (not done):
if (there is a schema R_i, in result that is not in BCNF):
let a -> B be a nontrivial functional dependency that holds on R_i such that a -> R_i is not in F+ and a intersection B = empty set
else:
done = True

Third Normal Form

  • A relation schema RR is in third normal form (3NF) if for all:
    • αβ\alpha \to \beta in F+F+
    • at least one of the following holds:
      • αβ\alpha \to \beta is trivial
      • α\alpha is superkey for RR
      • Each attribute AA in βα\beta - \alpha is contained in a candidate key for RR
  • if a relation is in BCNF it is in 3NF (since in BCNF one of the first two conditions above must hold)
  • third condition is a minimal relaxation of BCNF to ensure dependency preservation (will see why later)

There are some situations where

  • BCNF is not dependency preserving
  • efficient checking for FD violation on updates is important

Solution: define a weaker normal form, called Third Normal Form (3NF)

  • allows some redundancy (with resultant)
  • but functional dependencies can be checked on individual relations without computing a join
  • there is always a lossless-join, dependency-preserving decomposition into 3NF

3NF Decomposition Algorithm

Let Fc be a canonical cover for F;
i := 0;
for each functional dependency a -> B in Fc do:
if none of the schemas Rj, 1 <= j <= i contains a B:
i := i + 1;
Ri := a B
if none of the schemas Rj, 1 <= j <= i contains a candidate key for R:
i := i + 1;
Ri := any candidate key for R;
/* Optionally, remove redundant relations */
repeat
if any schema Rj is contained in another schema Rk
/* delete Rj */
Rj = R;;
i=i-1;
return (R1, R2, ..., Ri)

Above algorithm ensures

  • each relation schema RjR_j is in 3NF
  • decomposition is dependency preserving and lossless-join
  • proof of correctness

Comparison of BCNF and 3NF

  • Advantages to 3NF over BCNF. It is always possible to obtain a 3NF design without sacrificing losslessness or dependency preservation.

  • Disadvantages to 3NF

    • We may have to use null values to represent some of the possible meaningful relationships among data items
    • there is the problem of repetition of information

Goals of Normalization

  • Let RR be a relation scheme with a set FF of functional dependencies
  • Decide whether a relation scheme RR is in "good" form
  • In the case that a relation scheme RR is not in "good" form, need to decompose it into a set of relation scheme R1,R2,...,RnR_1, R_2, ..., R_n such that:
    • each relation scheme is in good form
    • the decomposition is a lossless decomposition
    • preferably, the decomposition should be dependency preserving

Functional-Dependency Theory Roadmap

  • formal theory that tells us which dependencies are implied logically by a given set of functional dependencies
  • algorithms to generate lossless decompositions into BCNF and 3NF
  • algorithms to test if a decomposition is a dependency-preserving

Closure of a Set of Functional Dependencies

We can compute F+F+, the closure of FF, by repeatedly applying Armstrong's Axioms:

  • reflexive rule: if βα\beta \subseteq \alpha, then αβ\alpha \to \beta
  • augmentation rule: if αβ\alpha \to \beta, then γαγβ\gamma \alpha \to \gamma \beta
  • transitivity rule: if αβ\alpha \to \beta, and βγ\beta \to \gamma, then αγ\alpha \to \gamma
  • These rules are:
    • Sound: generate only functional dependencies that actually hold
    • Complete: generate all functional dependencies that hold
    • Union: if αβ\alpha \to \beta and αγ\alpha \to \gamma holds, then αβγ\alpha \to \beta \gamma holds.
    • Decomposition: if αβγ\alpha \to \beta \gamma holds, then αβ\alpha \to \beta holds and αγ\alpha \to \gamma holds
    • Pseudotransitivity: if αβ\alpha \to \beta holds and γβσ\gamma \beta \to \sigma holds, then αγσ\alpha \gamma \to \sigma holds.
  • The above rules can be inferred from Armstrong's axioms

Procedure for Computing F+

  • To compute the closure of a set of functional dependencies FF:
F+ = F
while F+ does not change any further
for each functional dependency f in F+:
apply reflexivity and augmentation rules on F
add the resulting functional dependencies to F+
for each pair of functional dependencies f1 and f2 in F+:
if f1 and f2 can be combined using transitivity:
add the resulting functional dependency to F+

Closure of Attribute Sets

  • Given a set of attributes α\alpha, the closure of α\alpha under FF (denoted by α+\alpha+) is the set of attributes that are functionally determined by α\alpha under FF
  • Algorithm to compute α+\alpha+, the closure of α\alpha under FF
result = a
while (changes to result):
for each beta in gamma in F:
if beta is a super set of result:
result = result union gamma

Uses of Attribute Closure

There are several uses of the attribute closure algorithm:

  • Testing for superkey
    • to test if α\alpha is a superkey, we compute α+\alpha+ and check if alpha+alpha+ contains all attribute of RR
  • Testing functional dependencies
    • to check if a functional dependency αβ\alpha \to \beta holds, check if βα+\beta \subseteq \alpha+
    • we compute α+\alpha+ by using attribute closure, and then check if it contains β\beta
    • this is a simple and cheap test, and very useful
  • computing closure of FF
    • for each γR\gamma \subseteq R, we find the closure γ+\gamma+, and for each Sγ+S \subseteq \gamma+, we output a functional dependency γS\gamma \to S

Canonical Cover

  • Suppose that we have a set of functional dependencies FF on a relation schema. Whenever a user performs an update on the relation, the database system must ensure that the update does not violate any functional dependencies; that is, all the functional dependencies in FF are satisfied in the new database state.
  • If an update violates any functional dependencies in the set FF, the system must roll back the update.
  • We can reduce the effort spent in checking for violations by testing a simplified set of functional dependencies that has the same closure as the given set.
  • This simplified set is termed the canonical cover
  • To define canonical cover we must first define extraneous attributes.
  • An attribute of a functional dependency in FF is extraneous if we can remove it without changing F+F+

To compute a canonical cover for FF:

repeat
Use the union rule to replace any dependencies in F
Find a functional dependency in F with an extraneous attribute either in a or in B
If an extraneous attribute is found, delete it from a -> B
until F not change

A canonical cover for FF is a set of dependencies FcF_c such that:

  • FF logically implies all dependencies in FcF_c
  • FcF_c logically implies all dependencies in FF
  • No functional dependency in FcF_c contains an extraneous attribute
  • Each left side of functional dependency in FcF_c is unique. There are no two dependencies in FcF_c

Extraneous attributes

  • Removing an attribute from the left side of a functional dependency could make it a stronger constraint. Depending on what our set FF of functional dependencies happens to be, we may be able to remove BB from ABCAB \to C safely.
  • Removing an attribute from the right side of a functional dependency could make it a weaker constraint. Depending on what our set FF of functional dependencies happens to be, we may able to remove CC from ABCDAB \to CD safely

An attribute of a functional dependency in FF is extraneous if we can remove it without changing F+F+

Testing if an Attribute is Extraneous

Let RR be a relation schema and let FF be a set of functional dependencies that hold on RR. Consider an attribute in the functional dependency αβ\alpha \to \beta

  • To test if AβA \in \beta is extraneous in β\beta
    • Consider the set:
      • $F' = (F - {\alpha \to \beta}) \cup {\alpha \to (\beta - A)}
      • check that α+\alpha+ contains AA under FF'; if it does, A is extraneous in β\beta
  • To test if AalphaA \in alpha is extraneous in α\alpha
    • Let γ=αA\gamma = \alpha - {A}. Check if γβ\gamma \to \beta can be inferred from FF
      • Compute γ+\gamma+ using the dependencies in FF
      • IF γ+\gamma+ includes all attributes in β\beta then, A is extraneous in α\alpha

Design Goals

  • Goal for a relational database design is:
    • BCNF.
    • Lossless join.
    • Dependency preservation.
  • If we cannot achieve this, we accept one of
    • Lack of dependency preservation
    • Redundancy due to use of 3NF
  • Interestingly, SQL does not provide a direct way of specifying functional dependencies other than superkeys. Can specify FDs using assertions, but they are expensive to test, (and currently not supported by any of the widely used databases!)
  • Even if we had a dependency preserving decomposition, using SQL we would not be able to efficiently test a functional dependency whose left hand side is not a key.

Dependency Preservation

Let FiF_i be the set of dependencies in F+F+ that include only attributes in RiR_i.

  • A decomposition is dependency preserving, if (F1F2...Fn)+=F+(F_1 \cup F_2 \cup ... \cup F_n)+ = F+

Using the above definition, for testing for dependency preservation takes exponential time. Note that if a decomposition is NOT dependency preserving then checking updates for violation of functional dependencies may require computing joins, which is expensive.

  • Let FF be the set of dependencies on schema RR and let R1,R2,..,RnR_1, R_2 , .., R_n be a decomposition of RR.
  • The restriction of F to Ri is the set $F_i of all functional dependencies in F+F+ that include only attributes of RiR_i.
  • Since all functional dependencies in a restriction involve attributes of only one relation schema, it is possible to test such a dependency for satisfaction by checking only one relation.
  • Note that the definition of restriction uses all dependencies in F+F+, not just those in FF.
  • The set of restrictions F1,F2,..,FnF1, F_2 , .. , F_n is the set of functional dependencies that can be checked efficiently.

Testing for Dependency Preservation

Checking (F1F2Fn)+=F+(F1 \cup F2 \cup … \cup Fn)+ = F+ is expensive and since it requires the computation of FF.

Alternative 1:

  • If each member of F can be tested on one of the relations of the decomposition, then the decomposition is dependency preserving. However, this does not always work! This can be used as a sufficient condition, but if it fails we cannot conclude that the decomposition is not dependency preserving!

Alternative 2:

  • To check if a dependency αβ\alpha \to \beta is preserved in a decomposition of RR into R1,R2,...,RnR_1, R_2, ..., R_n, we apply the following test (with attribute closure done with respect to FF)
result = a
repeat
for each $R_i$ in the decomposition
t = (result intersection Ri)+ intersection Ri
result = result union t
until (result does not change)
If result contains all attributes in, then the functional dependency
a -> B is preserved.
  • We apply the test on all dependencies in FF to check if a decomposition is dependency preserving
  • This procedure takes polynomial time, instead of the exponential time required to compute F+F+ and (F1F2...Fn)+(F_1 \cup F2 \cup ... \cup Fn)+

Multi-valued Dependencies

A multi-valued dependency (MVD) on R,X>YR, X -> Y says that: if two tuples of RR agree on all the attributes of XX, then their components in YY may be swapped, and the result will be two tuples that are also in the relation, i.e., for each value of XX, the values of YY are independent of the values RXYR-X-Y.

Let RR be a relation schema and let αR\alpha \subseteq R and βR\beta \subseteq R. The multi-valued dependency α>β\alpha -> \beta holds on RR if in any legal relation r(R)r(R), for all pairs for tuples t1t_1 and t2t_2 in rr such that t1[α]=t2[α]t_1[\alpha] = t_2[\alpha], there exist tuples t3t_3 and t4t_4 in rr such that:

t1[a] = tt2[a] = t3[a] = t4[a]
t3[B] = t1[B]
t3[R-B] = t2[R-B]
t4[B] = t2[B]
t4[R-B] = t1[R-B]

Let RR be a relation schema with a set of attributes that are partitioned into 3 nonempty subsets Y,Z,WY, Z, W. We say that Y>Z(YY -> Z (Y multi-determines ZZ) if and only if for all possible relations r(R)<y1,z1,w1>rr(R) < y_1, z_1, w_1> \in r and <y1,z2,w2>r< y_1, z_2, w_2 > \in r then <y1,z1,w2>r< y_1, z_1, w_2> \in r and <y1,z2,w1>r< y_1, z_2, w_1 > \in r

Use of Multi-valued Dependencies

We use multi-values dependencies in two ways:

  1. To test relations to determine whether they are legal under a given set of functional and multi-valued dependencies
  2. To specify constraints on the set of legal relations. We shall concern ourselves only with relations that satisfy a given set of functional and multi-valued dependencies.

If a relation rr fails to satisfy a given multi-values dependency, we can construct a relation rr' that does satisfy the multi-valued dependency by adding tuples to rr.

Fourth Normal Form

A relation schema RR is in 4NF with respect to a set DD of functional and multi-valued dependencies if for all multi-valued dependencies in D+D+ of the form α>β\alpha -> \beta, where αR\alpha \subseteq R and βR\beta \subseteq R, at least one of the following hold:

  • α>beta\alpha -> beta is trivial (i.e., βsubseteqα\beta subseteq \alpha or αβ=R\alpha \cup \beta = R)
  • α\alpha is a superkey for schema RR

IF a relation is in 4NF it is in BCNF.

Decomposition Algorithm

result: = {R}
done := false
compute D+
Let Di denote the restriction of D+ to Ri
while (not done):
if (there is a schema Ri in result that is not in 4NF):
let a -> B be a nontrivial multivalued dependency that holds on Ri such that a -> Ri is not in Di and a intersection B = empty set
result := (result - Ri) union (Ri - B) union (a, B)
else:
done := true