SEN2104 · Week 11 · Relational Database Design

Decomposition: lossless join, dependency preservation, BCNF and 3NF algorithms

You learn to split a schema into pieces without losing data (lossless join), to test dependency preservation, and to apply the BCNF decomposition and 3NF synthesis algorithms step by step.

decompositionlossless-join decompositionlossy decompositionspurious tuplechase (tableau) testdependency preservationprojection of FBCNF decomposition algorithm3NF synthesis algorithm

Last week you learned to find the normal form of a schema. If the normal form is low, the fix is to split the schema into pieces (decomposition). But not every split is good. You want two things from a decomposition:

  1. Lossless join: when the pieces are joined back with NATURAL JOIN, you must get exactly the original table.
  2. Dependency preservation: every FD must be checkable in the individual pieces, without a join.

Typical exam questions: “Is this decomposition lossless?”, “Is it dependency preserving?”, “Decompose R into BCNF”, “Apply the 3NF synthesis algorithm”.

A lossy decomposition: seeing it in data

From the sample database, derive a table that holds each student’s department and the course they took (S7, whose department is NULL, is left out): enr(stu_id, dept_name, course_id), 13 rows. The only FD is stu_id→dept_name\text{stu\_id} \to \text{dept\_name}.

Now let us split it in the wrong place:

CREATE TABLE r1 AS SELECT DISTINCT stu_id, dept_name FROM enr;    -- 5 rows
CREATE TABLE r2 AS SELECT DISTINCT dept_name, course_id FROM enr; -- 10 rows
SELECT COUNT(*) FROM r1 NATURAL JOIN r2;
18

The 13-row table came back as 18 rows. You can see the excess with EXCEPT:

SELECT stu_id, dept_name, course_id FROM r1 NATURAL JOIN r2
EXCEPT SELECT * FROM enr;
stu_iddept_namecourse_id
S2CSCS305
S2CSMA101
S5CSCS201
S5CSCS305
S5CSMA101

These rows are called spurious tuples. Why only CS? The join is made on dept_name, and CS has three students (S1, S2, S5). r2 keeps the information “a CS student took this course” but has lost which student it was. EE and MATH each have a single student, so no mix-up occurs there.

PITFALL · “lossy” does not mean losing rows. In a lossy decomposition the join produces more rows. What is lost is information: you can no longer tell which rows are real.

The correct split: r1(stu_id, dept_name) and r3(stu_id, course_id). The intersection is stu_id, and since stu_id→dept_name\text{stu\_id} \to \text{dept\_name}, stu_id is the key of r1. r1 NATURAL JOIN r3 gives exactly 13 rows, and the EXCEPT result is empty.

The binary test

If you split RR into R1R_1 and R2R_2, the decomposition is lossless if and only if one of these FDs is in F+F^+:

R1∩R2→R1orR1∩R2→R2R_1 \cap R_2 \to R_1 \qquad \text{or} \qquad R_1 \cap R_2 \to R_2

That is, the intersection must be a superkey of one of the pieces. Calculation: take the closure of the intersection.

R(A,B,C,D)R(A,B,C,D), F={A→B, C→D}F = \{A \to B,\ C \to D\}:

DecompositionIntersectionClosureResult
(A,B), (A,C,D)A{A}+=AB⊇R1\{A\}^+ = AB \supseteq R_1lossless
(A,B,C), (C,D)C{C}+=CD⊇R2\{C\}^+ = CD \supseteq R_2lossless
(A,B), (C,D)emptyemptylossy
(A,B,D), (B,C)B{B}+=B\{B\}^+ = Blossy

Three or more pieces: the chase test

The binary test is only for two pieces. For more, use the tableau method:

  1. The columns are the attributes of R, with one row per piece.
  2. In each row, write a for the columns the piece contains and b (specific to the row) for the others.
  3. For each X→YX \to Y: for two rows that are equal on the X columns, equate their Y values (if one is a, both become a).
  4. Repeat until there are no changes. If a row consisting entirely of a’s appears, it is lossless.

Worked example. R(A,B,C,D,E)R(A,B,C,D,E), F={A→B, C→D, BD→E}F = \{A \to B,\ C \to D,\ BD \to E\}, pieces (A,B), (C,D), (A,C,E).

         A    B    C    D    E
R1(AB)   a    a    b    b    b
R2(CD)   b    b    a    a    b
R3(ACE)  a    b    a    b    a

A -> B : R1 and R3 are equal on A  → R3.B = a
C -> D : R2 and R3 are equal on C  → R3.D = a
R3     : a    a    a    a    a      → LOSSLESS

If you try (A,B), (C,D), (B,D,E) with the same F, no FD can be applied (there are no two rows equal on A or on C, and no two rows equal on BD), and no all-a row appears: lossy. An intuition (not a rule): in the first example the winning row was R3, which contains the candidate key AC. In the second example there is no piece that holds A and C together.

Dependency preservation

Let FiF_i be the projection of F+F^+ onto RiR_i: the FDs in F+F^+ all of whose attributes are inside RiR_i. A decomposition is preserving if (F1∪F2∪… )+=F+(F_1 \cup F_2 \cup \dots)^+ = F^+. Practical test: for each X→YX \to Y in F, take the closure of XX using only the projected FDs; if Y comes out, it is preserved.

Example 1. R(A,B,C,D)R(A,B,C,D), F={A→B, B→C, C→D}F = \{A \to B,\ B \to C,\ C \to D\}, pieces (A,B), (A,C), (C,D).

The projections: A→BA \to B, A→CA \to C, C→DC \to D. With this set {B}+={B}\{B\}^+ = \{B\}: B→CB \to C is lost. The decomposition is lossless but not preserving. If you had chosen the pieces (A,B), (B,C), (C,D), all three FDs would be inside a piece.

Example 2. R(A,B,C)R(A,B,C), F={A→B, B→C, C→A}F = \{A \to B,\ B \to C,\ C \to A\}, pieces (A,B), (B,C). No piece contains C→AC \to A. But since {B}+=ABC\{B\}^+ = ABC, there is B→AB \to A in the projection onto AB and C→BC \to B in the projection onto BC. C→B→AC \to B \to A: C→AC \to A is preserved.

PITFALL · the projection is not taken from F alone. When finding the FDs that fall in a piece, it is not enough to look at the list in F and ask “are the attributes of this FD in the piece?”. You must also think of the FDs coming from F+F^+; the way to do this is to take the closure of every subset in the piece.

The BCNF decomposition algorithm

result := {R}
while there is a Ri in result that is not in BCNF:
    find an X -> Y that holds in Ri and where X is not a superkey
    replace Ri with  (X+ ∩ Ri)  and  Ri − (X+ − X)

In every split the intersection is X and X is the key of the first piece, so the result is always lossless. Preservation is not guaranteed.

Worked example. R(A,B,C,D,E)R(A,B,C,D,E), F={A→B, BC→D, D→E}F = \{A \to B,\ BC \to D,\ D \to E\}. A and C are not on the right, and {A,C}+\{A,C\}^+ = ABCDE: the only key is AC. At each step we choose the shortest violating left side.

ABCDE : A -> B violates.  A+ ∩ Ri = AB         →  AB  and  ACDE
AB    : BCNF
ACDE  : D -> E violates.  D+ ∩ Ri = DE         →  DE  and  ACD
DE    : BCNF
ACD   : projection AC -> D, AC is a key        →  BCNF
Result: AB, DE, ACD

Preservation check: BC→DBC \to D. B and C are not in the same piece, and with the projections {B,C}+={B,C}\{B,C\}^+ = \{B,C\}. Lost. If you had started with D→ED \to E in the first step, you might have found a different result; decomposition is not unique, so write down the order you chose in the exam.

University example: wide(S, N, C, T, G) = (stu_id, stu_name, course_id, title, grade), F={S→N, C→T, SC→G}F = \{S \to N,\ C \to T,\ SC \to G\}. The algorithm gives CT, NS and CGS: course(course_id, title), student(stu_id, stu_name), takes(stu_id, course_id, grade). This time all three FDs are preserved; this is the answer to why the tables we use in the course are split this way.

The 3NF synthesis algorithm

1. Find the canonical cover Fc of F
2. For every X -> Y in Fc, create a schema (X ∪ Y)
3. If no schema contains a candidate key of R, add a candidate key as a separate schema
4. Delete the schemas that are a subset of another schema

The result is a 3NF decomposition that is both lossless and dependency preserving.

The same example: Fc={A→B, BC→D, D→E}F_c = \{A \to B,\ BC \to D,\ D \to E\} (nothing is redundant). The schemas are AB, BCD, DE. None contains AC, so add AC. The result is AB, BCD, DE, AC. The chase test says lossless, and each of the three FDs is inside a piece. In this example all the pieces even came out as BCNF; this is not always the case.

BCNF or 3NF?

BCNF decomposition3NF synthesis
Losslessalwaysalways
Dependency preservationnot guaranteedalways
Redundancyno FD-caused redundancysome may remain

The classic dilemma: tutoring(stu_id, subject, tutor_id), tutor_id→subject\text{tutor\_id} \to \text{subject}, {stu_id, subject}→tutor_id\{\text{stu\_id, subject}\} \to \text{tutor\_id}. BCNF decomposition gives (tutor_id, subject) and (stu_id, tutor_id). It is lossless, but the rule “a student has a single tutor in a subject” can no longer be checked in a single table. The designer often chooses to stay in 3NF and keep this rule enforceable.

Common mistakes

Wrong ideaThe truth
A lossy join loses rowsIt produces extra (spurious) rows, and information is lost
If the intersection is not empty, it is losslessThe intersection must be a superkey of a piece
Applying the binary test to 3+ piecesUse the chase tableau
If no piece contains the FD, it is not preservedThe projection is taken from F+F^+; it can be derived through a chain
BCNF decomposition preserves dependenciesIt is lossless but may not preserve
Skipping the key step in 3NF synthesisIf no piece contains a key, it can be lossy
BCNF decomposition has a single answerThe order in which violations are chosen can give different results

Test yourself

Exam-style questions. Solve them on paper first, then reveal the answer.

Question 1easy

Let R(A,B,C,D)R(A,B,C,D) with F={A→B, C→D}F = \{A \to B,\ C \to D\}. Is the decomposition R1(A,B)R_1(A,B), R2(A,C,D)R_2(A,C,D) lossless?

Show answer
Yes

Binary test: R1∩R2={A}R_1 \cap R_2 = \{A\}. {A}+={A,B}\{A\}^+ = \{A,B\}, so A→AB=R1A \to AB = R_1. The intersection is a superkey of one of the pieces: lossless.

Question 2easy

Same RR and FF. Is the decomposition R1(A,B)R_1(A,B), R2(C,D)R_2(C,D) lossless?

Show answer
No (lossy)

The intersection is the empty set. The empty set determines nothing, the join turns into a Cartesian product and produces rows that are not in the original. Lossy.

Question 3medium

Same RR and FF. Is R1(A,B,D)R_1(A,B,D), R2(B,C)R_2(B,C) lossless?

Show answer
No (lossy)

The intersection is {B}. {B}+={B}\{B\}^+ = \{B\}: B determines neither R1R_1 nor R2R_2. The binary test fails, so it is lossy.

Question 4medium

Table enr(stu_id, dept_name, course_id) is split into r1(stu_id, dept_name) and r2(dept_name, course_id). S5 is a CS student who took only CS101. The CS students in enr took CS101, CS201, CS305 and MA101. After r1 NATURAL JOIN r2, which spurious courses appear for S5?

Show answer
CS201, CS305, MA101

The join is made on dept_name. S5 → CS, CS → {CS101, CS201, CS305, MA101}. So the join produces four courses for S5; S5 took only CS101, and the other three are spurious tuples. The intersection dept_name is the key of neither piece, so it is lossy. In the whole table, 13 real rows grow to 18, with 5 spurious.

Question 5medium

Let R(A,B,C,D,E)R(A,B,C,D,E) with F={A→B, C→D, BD→E}F = \{A \to B,\ C \to D,\ BD \to E\}. Use the chase (tableau) test to decide whether R1(A,B)R_1(A,B), R2(C,D)R_2(C,D), R3(A,C,E)R_3(A,C,E) is lossless.

Show answer
Lossless

Tableau: one row per piece; write a for the columns in the piece and b for the others.
R1: a a b b b, R2: b b a a b, R3: a b a b a.A→BA \to B: R1 and R3 are equal on A, so R3's B becomes a. C→DC \to D: R2 and R3 are equal on C, so R3's D becomes a. R3 = a a a a a. A row of all a's appeared: lossless.

Question 6hard

Same RR and FF. Is R1(A,B)R_1(A,B), R2(C,D)R_2(C,D), R3(B,D,E)R_3(B,D,E) lossless?

Show answer
No (lossy)

Tableau: R1: a a b b b, R2: b b a a b, R3: b a b a a.A→BA \to B: there are no two rows equal on A. C→DC \to D: there are no two rows equal on C. BD→EBD \to E: R1 and R3 are equal on B but different on D. No FD can be applied and no row is all a. Lossy. (Also, no piece contains both A and C; the key AC is in no piece.)

Question 7medium

Let R(A,B,C,D)R(A,B,C,D) with F={A→B, B→C, C→D}F = \{A \to B,\ B \to C,\ C \to D\} and the decomposition (A,B)(A,B), (A,C)(A,C), (C,D)(C,D). Is it dependency preserving? If not, which FD is lost?

Show answer
No; B -> C is lost

Projections: A→BA \to B in AB; A→CA \to C in AC; C→DC \to D in CD. With this set, {B}+={B}\{B\}^+ = \{B\}, with no C. B→CB \to C cannot be checked in any piece and cannot be derived: not preserved. (The decomposition is still lossless.)

Question 8hard

Let R(A,B,C)R(A,B,C) with F={A→B, B→C, C→A}F = \{A \to B,\ B \to C,\ C \to A\}, decomposed into (A,B)(A,B) and (B,C)(B,C). No piece contains both CC and AA. Is C→AC \to A preserved?

Show answer
Yes

The projection includes not only the FDs in F but also those coming from F+F^+. Projection onto AB: A→BA \to B and B→AB \to A (because {B}+=ABC\{B\}^+ = ABC). Projection onto BC: B→CB \to C, C→BC \to B. With this set, {C}+\{C\}^+: C→BC \to B, B→AB \to A, and A is in it. C→AC \to A is preserved. Lesson: "no piece contains the FD" does not mean "not preserved".

Question 9hard

Let R(A,B,C,D,E)R(A,B,C,D,E) with F={A→B, BC→D, D→E}F = \{A \to B,\ BC \to D,\ D \to E\}. Decompose RR into BCNF (at each step use the shortest violating left side). Is the result dependency preserving?

Show answer
AB, DE, ACD; not preserving (BC -> D lost)

The key is AC. 1) A→BA \to B violates, {A}+=AB\{A\}^+ = AB: R → AB and ACDE.
2) In ACDE, D→ED \to E violates ({D}+=DE\{D\}^+ = DE): DE and ACD.
3) ACD: the only FD is AC→DAC \to D, AC is a key, so BCNF.
Result AB, DE, ACD. For BC→DBC \to D: B and C are not in the same piece, and with the projections {B,C}+={B,C}\{B,C\}^+ = \{B,C\}. Not preserved.

Question 10hard

Same RR and FF. Apply the 3NF synthesis algorithm.

Show answer
AB, BCD, DE, AC

The canonical cover is already {A→B, BC→D, D→E}\{A \to B,\ BC \to D,\ D \to E\}. One schema for each FD: AB, BCD, DE. None contains the candidate key AC, so add AC. None is a subset of another, so nothing is deleted. The result is lossless and preserves dependencies (in this example all the pieces are even BCNF).

Question 11medium

tutoring(stu_id, subject, tutor_id) has FDs tutor_id -> subject and stu_id, subject -> tutor_id. Give its BCNF decomposition and the FD that is no longer enforceable in a single table.

Show answer
(tutor_id, subject), (stu_id, tutor_id); stu_id, subject -> tutor_id is lost

tutor_id→subject\text{tutor\_id} \to \text{subject} breaks BCNF. {tutor_id}+\{\text{tutor\_id}\}^+ = {tutor_id, subject}: one piece is (tutor_id, subject), the other is (stu_id, tutor_id). The intersection tutor_id is the key of the first piece: lossless. But stu_id and subject are no longer in the same table; the rule "a student has a single tutor for a subject" cannot be checked without a join. That is why the schema can be left in 3NF.

Question 12hard

Let R(A,B,C,D)R(A,B,C,D) with F={AB→C, C→D, D→A}F = \{AB \to C,\ C \to D,\ D \to A\}. Decompose into BCNF (shortest violating left side first) and name a lost dependency.

Show answer
AD, CD, BC; AB -> C is lost

The keys are AB, BC, BD (3NF but not BCNF). 1) The derived FD C→AC \to A violates ({C}+=ACD\{C\}^+ = ACD, C is alphabetically first among single letters): ACD and BC.
2) In ACD, D→AD \to A violates (D is not a superkey): AD and CD.
3) AD, CD, BC have two attributes each, so BCNF.AB→CAB \to C: A and B are not in the same piece, and with the projections {A,B}+={A,B}\{A,B\}^+ = \{A,B\}. Not preserved. Losslessness is verified with the chase.

Verification: The lossy/lossless join example was counted on the sample database with node:sqlite by running NATURAL JOIN and EXCEPT; the binary test, the chase test, dependency preservation (with FD projection), the BCNF decomposition trace and the 3NF synthesis were computed with verify/SEN2104/lib.mjs (verify/SEN2104/11.mjs, 52 checks, 0 errors). In BCNF decomposition, at each step the shortest (alphabetically first if tied) violating left side was chosen.

Review card

A good decomposition: 1) lossless (lossless join) 2) dependency preserving Lossy = the join produces EXTRA rows (spurious), not missing ones Binary test: R1 ∩ R2 → R1 or R1 ∩ R2 → R2 (the intersection is a superkey of one piece) 3+ pieces: chase tableau; equate with each FD; if an all-a row appears it is lossless Preservation: every FD must be derivable from the union of the PROJECTIONS onto the pieces (projection of F+!) BCNF algorithm: find a violating X -> Y; split Ri into (X+ ∩ Ri) and Ri − (X+ − X); repeat BCNF decomposition: always lossless, preservation NOT GUARANTEED 3NF synthesis: canonical cover; a schema XY for every X -> Y; add a key if none; delete subsets 3NF synthesis: lossless + preserving, but some redundancy may remain Decomposition is not unique: which violation you pick first changes the result