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 |
DeparmentEmployee
| -> | 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
SalaryDeparmentEmployeeProjectMember
- 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