18 - Decomposition (Lossless & Dependency-Preserving)
1788 words
9 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# 18 - Decomposition (Lossless & Dependency-Preserving) ## 🎯 Learning Objectives After reading this topic, you will be able to: - Explain lossless vs. lossy decomposition - Test whether a decomposition is lossless - Test whether a decomposition preserves dependencies - Apply the 3NF synthesis algorithm ## 📋 Prereq...

18 - Decomposition (Lossless & Dependency-Preserving)
🎯 Learning Objectives
After reading this topic, you will be able to:
- Explain lossless vs. lossy decomposition
- Test whether a decomposition is lossless
- Test whether a decomposition preserves dependencies
- Apply the 3NF synthesis algorithm
📋 Prerequisites
- 16 - Normalization (1NF-3NF) — Normal forms, FDs
- 15 - Canonical Cover — Canonical cover computation
📖 Core Content
18.1 Intuition: Splitting Relations Correctly
When you decompose a relation (split it into smaller tables), two things can go wrong:
- Lossy join: When you join the decomposed tables back, you get MORE rows than the original (spurious tuples)
- FD loss: The decomposed tables don't allow checking all original FDs, so updates could violate constraints A GOOD decomposition must be:
- Lossless: The natural join of the projections must equal the original relation
- Dependency-preserving: All original FDs can be checked on the decomposed relations
Why This Matters: A bad decomposition is WORSE than no decomposition — it can silently produce wrong results.
18.2 Lossless Join Decomposition
Definition: Decomposition of R into R₁, R₂, ..., Rₙ is lossless if:
For binary decomposition (R→R1,R2): The decomposition is lossless iff:
(Where → means functional dependency.)
Chase test (general case): A systematic method to check lossless join.
18.3 Testing Lossless Join (Binary)
Algorithm:
- Check if R1∪R2=R (all attributes preserved)
- Check if R1∩R2=∅ (there's some common attribute)
- Check if R1∩R2→R1 or R1∩R2→R2 If all three conditions hold, the decomposition is lossless.
Worked Example
R(A,B,C,D,E) with F={AB→C,C→D,B→E}
Decomposition 1: R1(A,B,C), R2(D,E)
- R1∪R2={A,B,C,D,E}=R ✓
- R1∩R2=∅ ✗
- Lossy! Decomposition 2: R1(A,B,C,D), R2(B,E)
- R1∪R2={A,B,C,D,E}=R ✓
- R1∩R2={B}=∅ ✓
- {B}+ using F: {B} → B→E → {B, E}. Not all of R₁ or R₂.
- But check: Does B→R2? R₂ = {B, E}. {B}+ = {B, E} = R₂! Yes!
- Lossless!
18.4 Dependency Preservation
Definition: A decomposition preserves dependencies if the union of all FDs that can be verified on the decomposed relations is equivalent to the original FD set.
Testing: For each FD X→Y in F:
- Compute X+ using only FDs that can be checked on the decomposed relations
- If Y⊆X+, the FD is preserved
- All FDs must be preserved for the decomposition to be dependency-preserving Simpler approach: For each relation Ri, project the FDs onto Ri (keep only FDs where both sides are in Ri). If the union of these projected FDs is equivalent to F, the decomposition preserves dependencies.
Worked Example
R(A,B,C) with F={A→B,B→C}
Decomposition: R1(A,B), R2(A,C)
FDs on R1: A→B FDs on R2: None (A and C have no direct FD, only transitive)
Can we derive B→C from {A→B}? No! So this decomposition is NOT dependency-preserving.
Better decomposition: R1(A,B), R2(B,C)
- FDs on R1: A→B
- FDs on R2: B→C
- All original FDs are preserved. ✓
18.5 Lossless vs. Dependency-Preserving
Key insight: These two properties are INDEPENDENT:
- A lossless decomposition may NOT preserve dependencies
- A dependency-preserving decomposition may be lossy Goal: Get BOTH properties. | BCNF | Guarantees lossless | Does NOT guarantee dependency preservation | | 3NF | Guarantees lossless | Guarantees dependency preservation |
18.6 3NF Synthesis Algorithm
This algorithm produces a lossless, dependency-preserving 3NF decomposition:
sqlInput: R (relation), F (FD set) Output: 3NF decomposition 1. Compute canonical cover F_c of F 2. For each FD X → Y in F_c, create relation R_i = X ∪ Y 3. If no relation contains a candidate key of R, add a relation with a candidate key 4. Optimize: Merge any two relations where one is a subset of the other 5. The resulting decomposition is lossless and dependency-preserving
Worked Example
R(A,B,C,D) with F={A→B,A→C,B→D}
Step 1: Canonical cover. Fc={A→B,B→D} (A→C is redundant).
Step 2: Create relations for each FD:
- A→B → R1(A,B)
- B→D → R2(B,D) Step 3: Check if any relation contains a candidate key. CK = {A, C}. No relation has {A, C}. Add R3(A,C). Step 4: No merges needed. Final 3NF: R1(A,B), R2(B,D), R3(A,C)
18.7 Lossless Join Test (Chase) for Multiple Relations
For more than two relations, use the chase test:
- Create a table with one row per relation and columns for all attributes
- Fill each cell: If the attribute is in the relation, put a ; otherwise put
- Apply FDs: If two rows match on LHS, force equality on RHS
- If any row becomes all , the decomposition is lossless
📐 Key Formulas / Concepts
| Property | Binary Test | General Test |
|---|---|---|
| Lossless | R1∩R2→R1 or R1∩R2→R2 | Chase test |
| Dependency-preserving | All FDs checkable on individual relations | Project FDs, check equivalence |
⚠️ Common Pitfalls
Pitfall 1: Assuming Lossless Means "No Data Loss"
The Mistake: Thinking lossless means no information is lost.
Why It's Wrong: Lossless means the join returns exactly the original relation — no more rows. But you've "lost" the FD constraints that can't be checked on individual relations.
Correct: Lossless ≠ dependency-preserving. You need both.
Pitfall 2: Not Checking R1∪R2=R
The Mistake: Only checking the FD condition for losslessness.
Fix: First verify all attributes are covered: R1∪R2=R.
Pitfall 3: Thinking Decomposition Always Improves Design
The Mistake: Decomposing every relation to BCNF regardless of query patterns.
Why It's Wrong: Decomposition increases the number of JOINs needed in queries. Sometimes keeping a 3NF relation (with some redundancy) is better for performance than splitting it.
📝 Practice Questions
Q1. What makes a decomposition lossless? State the binary decomposition condition.
AnswerA binary decomposition of R into R₁ and R₂ is lossless iff:
- R1∪R2=R (all attributes covered)
- R1∩R2=∅ (common attributes exist)
- R1∩R2→R1 OR R1∩R2→R2 (common attributes determine one relation)
If satisfied, joining R₁ and R₂ will return exactly the original R without spurious tuples.
Q2. Check if decomposition of R(A,B,C,D) with F={A→B,B→C} into R1(A,B) and R2(C,D) is lossless.
Answer
- R1∪R2={A,B,C,D}=R ✓
- R1∩R2=∅ ✗
Condition 2 fails. The decomposition is lossy.Even without checking the FD condition, having no common attributes between the two relations means the Cartesian product will produce spurious tuples.
Q3. What does dependency preservation mean? Why is it important?
AnswerDependency preservation means all original FDs can be checked on the individual decomposed relations — no joins are needed to verify constraints.Importance: If a decomposition doesn't preserve dependencies, the DBMS must do JOINs to check FDs, which is expensive. Updates on the decomposed relations might violate FDs that can't be checked locally.Example: If F={A→B,B→C} and decomposition is R1(A,B), R2(A,C), the FD B→C can't be checked on either relation alone.
Q4. Apply the 3NF synthesis algorithm to R(A,B,C,D) with F={A→B,C→D}.
AnswerStep 1: Canonical cover. F is already minimal: Fc={A→B,C→D}.Step 2: Create relations:
- A→B → R1(A,B)
- C→D → R2(C,D)
Step 3: Check for candidate key. CK = {A, C}. Add R3(A,C).Step 4: No merges.Final 3NF: R1(A,B), R2(C,D), R3(A,C) — lossless and dependency-preserving.
Q5. Is it possible to have a lossless decomposition that doesn't preserve dependencies?
AnswerYes! These properties are independent. Example:R(A,B,C) with F={A→B,B→C}. Decompose into R1(A,B) and R2(A,C).
- Lossless? R1∩R2={A}, {A}+={A,B,C}=R1? Wait, R1 is just {A,B}. {A}+ in F = {A,B,C}, so {A}+ contains R1. ✓ Lossless.
- Dependency-preserving? B→C can't be checked on either R1 or R2 (B not in R2, C not in R1). ✗
This is lossless but NOT dependency-preserving.
Q6. What is the chase test used for?
AnswerThe chase test is a general method to check lossless join for decompositions involving more than two relations. It creates a symbolic table tracking which relations can supply which attributes, and uses FDs to deduce equality constraints. If any row becomes entirely marked, the decomposition is lossless.
Q7. Find a lossless, dependency-preserving 3NF decomposition of R(A,B,C,D) with F={A→BC,B→D}.
AnswerCanonical cover: Decompose A→BC → A→B,A→C. Fc={A→B,A→C,B→D}.Synthesis:
- A→B → R1(A,B)
- A→C → Already covered? R1 has A,B but not C. Make R2(A,C) Actually merge: A→B and A→C can be combined: R1(A,B,C)
- B→D → R2(B,D)
Check candidate key: CK = ? Compute: A⁺ = {A,B,C,D} = R → {A} is a CK. Already covered by R1 (which has A). No need to add extra relation.Final: R1(A,B,C), R2(B,D) — both in 3NF, lossless, dependency-preserving.
Q8. Why is the 3NF synthesis algorithm preferred over BCNF decomposition?
AnswerThe 3NF synthesis algorithm guarantees BOTH lossless join AND dependency preservation. BCNF decomposition guarantees lossless join but may lose FDs.In practice, if you need to preserve all FDs (which you usually do), 3NF synthesis is the safer choice. If BCNF is achievable while preserving all FDs, it's preferred for its stronger guarantees.
🔗 Cross-References
- Next Topic: 19 - Application Design
- Previous Topic: 17 - BCNF & Higher Normal Forms
- Related: 14 - Functional Dependencies (basis for decomposition)
- Textbook: Silberschatz, Korth, Sudarshan — Chapter 8 (Relational Database Design) Join Discord Previous17 - BCNF & Higher Normal FormsNext19 - Application Design