Pohon keluarga (family tree) bukanlah struktur pohon biner sederhana. Dalam kenyataan riil genealogi (seperti pada sistem Kinova), kita menghadapi berbagai kasus relasi data yang rumit:
- Seorang anak memiliki 2 orang tua kandung (ayah & ibu), bukan 1 parent.
- Pernikahan ganda dan saudara tiri (half-siblings).
- Adopsi dan pernikahan antar keluarga jauh (cross-branch lineages).
Menyimpan relasi ini dengan kolom sederhana father_id dan mother_id pada tabel orang (persons) sering kali menyebabkan table lock dan kueri join bertingkat yang sangat lambat.
1. Skema Relasi: Entities vs Unions
Pendekatan terbaik dalam database relasional seperti PostgreSQL adalah memisahkan entitas individu (Persons) dari entitas ikatan keluarga (Family Unions / Marriages):
erDiagram
PERSONS ||--o{ UNION_MEMBERS : spouse
UNIONS ||--o{ UNION_MEMBERS : includes
UNIONS ||--o{ PERSONS : parent_of
PERSONS {
uuid id PK
string full_name
string gender
date birth_date
}
UNIONS {
uuid id PK
uuid union_type
date marriage_date
}
UNION_MEMBERS {
uuid union_id FK
uuid person_id FK
string role
}
2. Kueri Penelusuran Cepat dengan Recursive CTE
Untuk mengambil seluruh garis keturunan ke bawah (descendants) atau garis leluhur ke atas (ancestors) sampai $N$-generasi dalam satu kali kueri SQL, kita memanfaatkan fitur PostgreSQL WITH RECURSIVE (Common Table Expression):
WITH RECURSIVE family_lineage AS (
-- Base member (Anchor): Leluhur awal
SELECT id, full_name, 1 AS generation_level
FROM persons
WHERE id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'
UNION ALL
-- Recursive member: Telusuri anak-anak dari tiap generasi
SELECT p.id, p.full_name, fl.generation_level + 1
FROM persons p
INNER JOIN unions u ON p.parent_union_id = u.id
INNER JOIN union_members um ON um.union_id = u.id
INNER JOIN family_lineage fl ON fl.id = um.person_id
)
SELECT * FROM family_lineage ORDER BY generation_level ASC;
3. Optimasi Indexing & Performa
- Covering Index: Pasang B-Tree index pada
(parent_union_id, id)untuk mempercepat penggabungan rekursif. - Cycle Prevention: Gunakan klausa
CYCLE id SET is_cycle USING pathbawaan PostgreSQL 14+ untuk mencegah infinite loop jika terjadi anomali siklus pada data keluarga.