What about data normal forms?
- Avoid data duplication to reduce data redundancy
- Less data
- Avoid multiple updates - one source of truth
- Avoid data editing anomaly
- A more representative data model
Employee | Phone | Floor | Room № |
---|---|---|---|
Alice | 651435 | 1 | 20 b |
Bob | 4324234 | 3 | 30 a |
John | 534315 | 3 | 30 a |
3NF
----------+---------+---------+ | ||||||
Employee | Phone | Room ID | Room ID | Room № | Floor | |
----------+---------+---------+ | ||||||
Alice | 651435 | 1 | 1 | 20 b | 1 | |
Bob | 4324234 | 2 | 2 | 30 a | 3 | |
John | 534315 | 2 |
---|
Employee | Room | ||
id | -> | id | |
name | floor | ||
phone | room№ | ||
room_id | – |
Salary | Room | |||
id | id | <----+ | ||
employee | ----+ | floor | ||
date | room№ | |||
amount |
Deparment
Employee
-> | id | -> | id | ||
name | name | ||||
head | -+ | phone | |||
room_id | -+ |
+---------------------| department |
Project | Customer | |||
----------- | ------------ | |||
╔═> | id | ╔═> | id | |
║ | customer | ═════╝ | name | |
║ | name | phone | ||
║ | logo | |||
║ | ||||
║ | Member | |||
╚══ | project | |||
role | ||||
employee | ══════╗ | |||
║ | ||||
Salary | ║ | Room | ||
id | ║ | id | <══╗ | |
employee | ════╣ | floor | ║ | |
date | ║ | room№ | ║ | |
amount | ║ ║ | |||
║ ║ | ||||
Deparment | ║ | Employee | ║ | |
╔═> | id | ╠═> | id | ║ |
║ | name | ║ | name | ║ |
║ | head | ═╝ | phone | ║ |
║ | room_id | ═╝ | ||
╚═════════════════════ | department |
--------------------------------------------
Search: __________________ |
---|
John +1(991)33434 - Development Room 42 |
Year Salary: 100$ Lead: Max |
Projects: QA in Cars, Dev in Toys |
Ivan +1(991)4325355 - Management Room 36 |
Year Salary: 80$ Lead: Ken |
Projects: QA in Cars, Manager in Food |
--------------------------------------------
-- pseudo sql =)
select
employee
, sum(salary)
, array_agg(member)
...
from employee
join department on ..
join employee on ..
join salary on ..
join member on ..
join project on ..
group by employee
where
employee ilike $search
or member ilike $search
or project ilike $search
or department ilike $search
...
Employee |
---|
id |
name |
phone |
room_id |
department |
=salary |
=boss |
=member[] |
=fts |
Add subs/hooks for all related tables
Salary
Deparment
Employee
Project
Member
- Improve search
- Avoid joins and aggregations
- Avoid multiple or
- Simplify complex data relations and structure
Employee |
---|
id |
name |
phone |
room_id |
department |
=salary |
=boss |
=member[] |
=fts |
Normal form data:
-------------- ------------------ ------------------------ -----------------
Practitioner | <-+- | PractitionerRole | -> | Organization | -> | Organization | |
Иванов И.И. | Врач стоматолог | Стоматологическое отд. | Гор. стом. пол. |
-------------- | ------------------ ------------------------ -----------------
- | PractitionerRole | -> | Organization | -> | Organization |
Терапевт | Терапевт. отделение | ГКБ 1 |
------------------ ------------------------ -----------------
After denormalization:
-------------------------
Practitioner |
Иванов И.И. |
=Врач стоматолог |
=Стоматологическое отд. |
=Гор. стом. пол. |
=Терапевт |
=Терапевт. отделение |
=ГКБ 1 |
-------------------------
- Super easy
- Standarts conflict
- Integration
- Conflict existing ui forms/controllers
- Business Logic
- Heavy write load
----------
8kb page |
---|
1 ----- |
2 ----- |
3 ----- |
----------
Update row 1 and 2
----------
8kb page |
---|
-1 ------ |
-2 ------ |
3 ------ |
1*------ |
----------
8kb page |
---|
2*------ |
----------
----------
8kb page |
---|
1 ----- |
2 ----- |
3 ----- |
----------
Update row 1 insert too large object
----------
8kb page | |
---|---|
-1 ----- | |
2 ----- | |
1*------- | ---------------- |
----------
---------- --------------
8kb page | Toast | |
---------- | -------------- | |
-1 ----- | 1.1* ------- | |
2 ----- | 1.2* ------- | |
1* toast | ||
---------- --------------
EmployeeInfo |
---|
employee_id |
=phone |
=salary |
=boss |
=member[] |
=fts |
----------- --------------- --------- --------- -------- -------------- -----------------
Condition | <- | EpisodeOfCare | -> | Patient | <- | Binding | -> | Sector | -> | Practitioner | -> | PractitonerRole |
----------- --------------- --------- --------- -------- -------------- -----------------
--------- --------- -------- -------------- -----------------
Patient | <- | Binding | -> | Sector | -> | Practitioner | -> | PractitonerRole |
--------- --------- -------- -------------- -----------------
PatientBinding |
---|
patient_id |
sector_id |
practitionerrole_id |
--------- --------------- -----------
Patient | <- | EpisodeOfCare | -> | Condition |
--------- --------------- -----------
PatientCondition |
---|
patient_id |
condition_type |
- Less and easiera update logic
- No update logic
- Explicit denormalization
- Less toast risk
-- pseudo sql
drop table if exists denormalization.patientbinding;
CREATE TABLE if not exists denormalization.patientbinding (like public.patientbinding);
insert into denormalization.patientbinding (patient_id, sector_id, practitionerrole)
select patient.id ....
from patient
join binding on ..
join sector on ..
join practitioner on ..
join practitionerrole on ..;
create index patientbinding_patient_id on denormalization.patientbinding (patient_id);
create index patientbinding_sector_id on denormalization.patientbinding (sector_id);
BEGIN;
-- Drop target table
drop table public.patientbinding;
-- Replace target table on public schema wiht temp table
alter table denormalization.patientbinding set schema public;
COMMIT;
- Use denormalization careful
- Database maintenance
- Try to decomposit your complex task
PG bloating - https://www.youtube.com/watch?v=-GNHIHEHDmQ&t=2361s&ab_channel=HighLoadChannel PG autovacuum -https://www.youtube.com/watch?v=TDWC66qzxCs&ab_channel=HighLoadChannel