ЁЯзй рдзрдбрд╛ 05 тАФ Data modelling: рдПрдХ рддрдереНрдп, рдПрдХ рдЬрд╛рдЧрд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 18 рдкреИрдХреА рдзрдбрд╛ 05 ┬╖ рдорд╛рдЧреЗ: lesson-04-transactions ┬╖ рдкреБрдвреЗ: lesson-06-indexes
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ04, рдЖрдгрд┐ рдиреЛрдВрджрд╡рд╣реНрдпрд╛ рдХреЛрдгрддреНрдпрд╛ рдЕрд╕рд╛рд╡реНрдпрд╛рдд рд╣реЗ рдХрд╕реЗ рдард░рд╡рд╛рдпрдЪреЗ: normalisation (рдПрдХ рддрдереНрдп, рдПрдХ рдЬрд╛рдЧрд╛), рд▓рд┐рдЦрд┐рдд рдирд┐рдпрдо рдореНрд╣рдгреВрди constraints, рдЖрдгрд┐ denormalisation тАФ рдПрдЦрд╛рджреА рдорд╛рд╣рд┐рддреА рдореБрджреНрджрд╛рдо copy рдХрд░рдгреЗ, рддреА рдЦрд░реА рдареЗрд╡рдгреНрдпрд╛рдЪреНрдпрд╛ рдирд┐рдпрдорд╛рд╕рд╣.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдПрдХ рдирд╡реА clerk рдПрдХрдЪ рдкреНрд░рдЪрдВрдб рдиреЛрдВрджрд╡рд╣реА рд╕реБрдЪрд╡рддреЗ: рдкреНрд░рддреНрдпреЗрдХ рдУрд│реАрдд рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА, рд╡рд░реНрдЧ, рд╢рд┐рдХреНрд╖рд┐рдХрд╛, рд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪрд╛ phone number, grade, рд╡рд┐рд╖рдптАж рд╡рд╛рдЪрд╛рдпрд▓рд╛ рд╕реЛрдкреЗ! рдордЧ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рдЖрдкрд▓рд╛ phone number рдмрджрд▓рддреЗ. рдореНрд╣рдгрдЬреЗ рддреАрд╕ рдУрд│реА рджреБрд░реБрд╕реНрдд рдХрд░рд╛рдпрдЪреНрдпрд╛, рдЖрдгрд┐ clerk рдПрдХреЛрдгрддреАрд╕ рджреБрд░реБрд╕реНрдд рдХрд░рддреЗ. рд╡рд░реНрд╖рднрд░ рдПрдХ рдУрд│ рдЦреЛрдЯреЗ рдмреЛрд▓рддреЗ.
рд╣реЗ рдЯрд╛рд│рдгрд╛рд░рд╛ рдирд┐рдпрдо: рдПрдХ рддрдереНрдп, рдПрдХ рдЬрд╛рдЧрд╛. рд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪрд╛ phone number teachers рдиреЛрдВрджрд╡рд╣реАрдЪреНрдпрд╛ рдПрдХрд╛рдЪ рдУрд│реАрдд рд░рд╛рд╣рддреЛ; рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдЖрдкрд▓реНрдпрд╛ рд╡рд░реНрдЧрд╛рдХрдбреЗ рдмреЛрдЯ рджрд╛рдЦрд╡рддрд╛рдд, рд╡рд░реНрдЧ рдЖрдкрд▓реНрдпрд╛ рд╢рд┐рдХреНрд╖рд┐рдХреЗрдХрдбреЗ. number рдПрдХрджрд╛ рдмрджрд▓рд╛, рдЖрдгрд┐ pointer рдордзреВрди join рд╣реЛрдгрд╛рд░рд╛ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрди рдирд╡рд╛ number рдкрд╛рд╣рддреЛ. рд╣реЗрдЪ normalisation, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдиреЛрдВрджрд╡рд╣реАрд╕рд╛рдареА рддреНрдпрд╛рдЪреЗ рддреАрди рдкреНрд░рд╢реНрди:
- рдПрдХ рдУрд│ рдореНрд╣рдгрдЬреЗ рдХрд╛рдп? (рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА тАФ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рд╖рдпрд╛рд╕рд╛рдареА рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдирд╡реНрд╣реЗ)
- рддреА рдХрд╢рд╛рдиреЗ рдУрд│рдЦрд▓реА рдЬрд╛рддреЗ? (рдУрд│ рдХреНрд░рдорд╛рдВрдХ; roll number
UNIQUEрдЖрд╣реЗ) - рдХреЛрдгрддреА рдорд╛рд╣рд┐рддреА рддрд┐рдЪреА рдЖрд╣реЗ, рддреА рдЬреНрдпрд╛рдХрдбреЗ рдмреЛрдЯ рджрд╛рдЦрд╡рддреЗ рддреНрдпрд╛рдЪреА рдирд╛рд╣реА? (рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреЗ рдирд╛рд╡: рд╣реЛ; рд╡рд░реНрдЧрд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪрд╛ phone: рдирд╛рд╣реА)
рдЖрдгрд┐ рдореБрджреНрджрд╛рдо рдХреЗрд▓реЗрд▓рд╛ рдЕрдкрд╡рд╛рдж: рдХрдзреАрдХрдзреА рдПрдЦрд╛рджрд╛ рдкреНрд░рд╢реНрди рдЗрддрдХреНрдпрд╛ рд╡реЗрд│рд╛ рд╡рд┐рдЪрд╛рд░рд▓рд╛ рдЬрд╛рддреЛ рдЖрдгрд┐ рдЗрддрдХреЗ join рдХрд░рддреЛ рдХреА рддреБрдореНрд╣реА рдПрдЦрд╛рджреА рдорд╛рд╣рд┐рддреА рддреА рдЬрд┐рдереЗ рд╡рд╛рдЪрд▓реА рдЬрд╛рддреЗ рддрд┐рдереЗрдЪ copy рдХрд░рддрд╛ тАФ рдПрдХ denormalised column тАФ рдЖрдгрд┐ рддреА copy рдЦрд░реА рдареЗрд╡рдгрд╛рд░рд╛ рдирд┐рдпрдо рддреБрдореНрд╣реА рд▓рд┐рд╣реВрди рдареЗрд╡рддрд╛ (trigger, рд░рд╛рддреНрд░реАрдЪрд╛ job, рдХрд┐рдВрд╡рд╛ "рдлрдХреНрдд рдпрд╛рдЪ рдПрдХрд╛ function рдордзреВрди"). рдХрд╛рд░рдг рдЖрдгрд┐ рдирд┐рдпрдо рдШреЗрдКрдирдЪ copy рдХрд░рд╛, рдХрдзреАрдЪ рдЪреБрдХреВрди рдирд╛рд╣реА.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
big["тЭМ one big register<br/>student ┬╖ class ┬╖ teacher ┬╖ teacher phone ┬╖ grade<br/>phone changes тЖТ 30 rows, 29 fixed"]
norm["тЬЕ one fact, one place<br/>teachers(id, name, phone) тЖР classes(teacher_id) тЖР students(class_id) тЖР grades(student_id)"]
rules["ЁЯзй constraints: NOT NULL ┬╖ UNIQUE ┬╖ CHECK ┬╖ FK<br/>the schema refuses nonsense"]
den["тЪЦя╕П denormalise on purpose<br/>copy a hot value + a rule that keeps it true"]
big -->|"1 normalise"| norm --> rules
norm -.->|"2 measured reason only"| den
тЭУ рдХрд╛рдп
- 1NF: рдкреНрд░рддреНрдпреЗрдХ cell рдордзреНрдпреЗ рдПрдХрдЪ value (рдПрдХрд╛ column рдордзреНрдпреЗ "maths, science" рдирдХреЛ тАФ
рддреА рдПрдХ
gradesрдиреЛрдВрджрд╡рд╣реА рдЖрд╣реЗ). рд╡реНрдпрд╡рд╣рд╛рд░рд╛рдд 2NF/3NF: key рдирд╕рд▓реЗрд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ column row рдЪреНрдпрд╛ key рдЪреЗ рд╡рд░реНрдгрди рдХрд░рддреЛ рдЖрдгрд┐ рджреБрд╕рд░реЗ рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА тАФ рдЬрд░ рддреЛ row рдЬреНрдпрд╛рдХрдбреЗ рдмреЛрдЯ рджрд╛рдЦрд╡рддреЗ рддреНрдпрд╛рдЪреЗ рд╡рд░реНрдгрди рдХрд░рдд рдЕрд╕реЗрд▓, рддрд░ рддреНрдпрд╛рдЪреА рдЬрд╛рдЧрд╛ рддрд┐рдереЗ рдЖрд╣реЗ. - Constraints рдореНрд╣рдгрдЬреЗрдЪ modelling:
CHECK (term IN (1,2,3)),UNIQUE (student_id, subject, term),NOT NULLтАФ domain рдЪреЗ рдирд┐рдпрдо рдХрдкрд╛рдЯрд╛рддрдЪ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ, рдкреНрд░рддреНрдпреЗрдХ program рд╕рд╛рдареА рд▓рд╛рдЧреВ. - Types рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: dates ISO strings (
2026-10-03) рдХрд┐рдВрд╡рд╛DATEрдореНрд╣рдгреВрди; рдкреИрд╕реЗ рд╕рд░реНрд╡рд╛рдд рд▓рд╣рд╛рди рдПрдХрдХрд╛рдд integers рдореНрд╣рдгреВрди, floats рдХрдзреАрдЪ рдирд╛рд╣реА; booleans0/1рдХрд┐рдВрд╡рд╛BOOLEANрдореНрд╣рдгреВрди. - Denormalisation: trigger рдиреЗ update рд╣реЛрдгрд╛рд░рд╛
students.grade_countcolumn; рд░рд╛рддреНрд░реАрдЪрд╛class_summarytable; hot read paths рд╡рд░ copy рдХреЗрд▓реЗрд▓реЗclass_name. рдореЛрдЬрд▓реЗрд▓реНрдпрд╛ рдХрд╛рд░рдгрд╛рд╕рд╣ (рдзрдбрд╛ 12) рдЖрдгрд┐ рдирд┐рдпрдорд╛рдЪрд╛ рдорд╛рд▓рдХ рдЕрд╕реЗрд▓ рддрд░рдЪ рдкрд░рд╡рд╛рдирдЧреА. - рдирд╛рд╡реЗ: tables рдЕрдиреЗрдХрд╡рдЪрдиреА (
students), columns snake_case, foreign keys<thing>_id. рдХрдВрдЯрд╛рд│рд╡рд╛рдгреА рдирд╛рд╡реЗ рдореНрд╣рдгрдЬреЗ рджрдпрд╛рд│реВрдкрдгрд╛.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг schema рддреЛ рд╡рд╛рдкрд░рдгрд╛рд▒реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ program рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЬрдЧрддреЛ. рдЪрд╛рдВрдЧрд▓реНрдпрд╛ model
рдХреЗрд▓реЗрд▓реНрдпрд╛ рдЦреЛрд▓реАрдд рдирд╡рд╛ рдкреНрд░рд╢реНрди рдПрдХрд╛ JOIN рдЪреНрдпрд╛ рдЕрдВрддрд░рд╛рд╡рд░ рдЕрд╕рддреЛ; рд╡рд╛рдИрдЯ model рдХреЗрд▓реЗрд▓реНрдпрд╛
рдЦреЛрд▓реАрдд рдкреНрд░рддреНрдпреЗрдХ рдирд╡рд╛ рдкреНрд░рд╢реНрди рдЖрдзреА data рд╕рд╛рдлрд╕рдлрд╛рдИ рдмрдирддреЛ. рдЖрдгрд┐ constraints "рд╣реЗ рдХреБрдареЗрддрд░реА
validate рдХрд░рд╛рдпрд▓рд╛ рд╣рд╡реЗ" рдпрд╛рдЪреЗ рд░реВрдкрд╛рдВрддрд░ "рдХрдкрд╛рдЯ рдЖрдзреАрдЪ рддреЗ рдХрд░рддреЗ" рдордзреНрдпреЗ рдХрд░рддрд╛рдд.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
db/schema.sql normalised рдЖрд╣реЗ: classes, students,
grades, homework, рдкреНрд░рддреНрдпреЗрдХ рдорд╛рд╣рд┐рддреА рдПрдХрджрд╛рдЪ, keys рдиреЗ рдЬреЛрдбрд▓реЗрд▓реА, UNIQUE рдЖрдгрд┐
CHECK рдирд┐рдпрдорд╛рдВрд╕рд╣. demo.py рдордзреАрд▓ model() рдХрдкрд╛рдЯ рджреЛрди рдкреНрд░рдХрд╛рд░рдЪрд╛ рдореВрд░реНрдЦрдкрдгрд╛ рдирд╛рдХрд╛рд░рддрд╛рдирд╛
рджрд╛рдЦрд╡рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ тАФ capstone рдЪрд╛ рдкрд╣рд┐рд▓рд╛ рджрдЧрдб
# 1) add a teachers register, properly: in db/schema.sql
# CREATE TABLE IF NOT EXISTS teachers (id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT);
# and give classes a pointer: teacher_id INTEGER REFERENCES teachers(id)
# 2) seed one teacher per class in db/seed.sql, rebuild, and ask:
python3 db/demo.py model >/dev/null
python3 - <<'EOF'
import sqlite3; c = sqlite3.connect("db/school.db")
print(c.execute("SELECT s.name, t.name, t.phone FROM students s JOIN classes c ON c.id=s.class_id JOIN teachers t ON t.id=c.teacher_id ORDER BY s.name").fetchall())
c.execute("UPDATE teachers SET phone='000' WHERE id=1"); c.commit() # change the fact ONCE
print(c.execute("SELECT DISTINCT t.phone FROM students s JOIN classes c ON c.id=s.class_id JOIN teachers t ON t.id=c.teacher_id WHERE c.id=1").fetchall())
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
3A рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреНрдпрд╛ рдУрд│реАрдд рддреАрдЪ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рдЖрдгрд┐ phone рджрд┐рд╕рддреЛ; teachers рд╡рд░ рдПрдХрд╛ UPDATE рдирдВрддрд░, joined query [('000',)] рджрд╛рдЦрд╡рддреЗ тАФ рдПрдХ рдмрджрд▓, рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрд▓рд╛ рджрд┐рд╕рддреЛ. рджреБрд╣реЗрд░реА roll number рдХрд┐рдВрд╡рд╛ Z рд╣рд╛ grade рдЕрдЬреВрдирд╣реА рдирд╛рдХрд╛рд░рд▓рд╛ рдЬрд╛рддреЛ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреБрдореНрд╣реА рдЦреЛрд▓реАрдд рдПрдХрд╛ рдирд╡реНрдпрд╛ рдкреНрд░рдХрд╛рд░рдЪреА рдорд╛рд╣рд┐рддреА рдПрдХрд╛рдЪ рдЬрд╛рдЧреА рдЬреЛрдбрд▓реА, рддреА key рдиреЗ рдЬреЛрдбрд▓реА, рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдВрд╕рд╛рдареА рдПрдХрджрд╛рдЪ рдмрджрд▓рд▓реА тАФ modelling рдЪрд╛ рдирд┐рдпрдо, рдЕрдиреБрднрд╡рд▓реЗрд▓рд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- column рдордзреНрдпреЗ рд╕реНрд╡рд▓реНрдкрд╡рд┐рд░рд╛рдорд╛рдиреЗ рд╡реЗрдЧрд│реНрдпрд╛ рдХреЗрд▓реЗрд▓реНрдпрд╛ рдпрд╛рджреНрдпрд╛ ("maths, science") тАФ рддреЛ рдПрдХ table рдЖрд╣реЗ
- key рд╣рд╡реА рддрд┐рдереЗ рдирд╛рд╡ copy рдХрд░рдгреЗ (
class_idрдРрд╡рдЬреАclass TEXT) - рдкреИрд╢рд╛рдВрд╕рд╛рдареА floats; рддреАрди formats рдордзреНрдпреЗ dates рд╕рд╛рдареА strings
- рдореЛрдЬрдгреНрдпрд╛рдЖрдзреАрдЪ "speed рд╕рд╛рдареА" denormalise рдХрд░рдгреЗ тАФ рдЖрдгрд┐ copy рдЦрд░реА рдареЗрд╡рдгрд╛рд▒реНрдпрд╛ рдирд┐рдпрдорд╛рд╢рд┐рд╡рд╛рдп
- domain рдРрд╡рдЬреА screen рдЪреЗ model рдХрд░рдгреЗ тАФ screens рджрд░ рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛ рдмрджрд▓рддрд╛рдд, domain рдмрджрд▓рдд рдирд╛рд╣реА
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: schema design рд╣рд╛ рдЕрд╕рд╛ рдПрдХрдореЗрд╡ рдирд┐рд░реНрдгрдп рдЖрд╣реЗ рдЬреЛ рдкрд╣рд┐рд▓реНрдпрд╛ рджрд┐рд╡рд╢реА рд╕реНрд╡рд╕реНрдд рдЕрд╕рддреЛ рдЖрдгрд┐ 400 рд╡реНрдпрд╛ рджрд┐рд╡рд╢реА рдмрджрд▓рдгреЗ рд╡рд┐рдирд╛рд╢рдХрд╛рд░реА рдЕрд╕рддреЗ. рдЖрдзреА normalise рдХрд░рдгрд╛рд▒реНрдпрд╛ рдЖрдгрд┐ рдкреБрд░рд╛рд╡реНрдпрд╛рд╕рд╣ denormalise рдХрд░рдгрд╛рд▒реНрдпрд╛ teams рдЖрдкрд▓реЗ рдкрд░реНрдпрд╛рдп рдЯрд┐рдХрд╡рддрд╛рдд; рдЙрд▓рдЯрд╛ рдХреНрд░рдо рдореНрд╣рдгрдЬреЗ rewrite.
тПня╕П рдкреБрдвреЗ
рдЦреЛрд▓реАрд▓рд╛ рдЪрд╛рдВрдЧрд▓рд╛ рдЖрдХрд╛рд░ рдЖрд▓рд╛ рдЖрд╣реЗ тАФ рдЖрддрд╛ рдкреНрд░рд╢реНрди рдЬрд▓рдж рдХрд░рд╛: indexes, рдХрд╛рд░реНрдб
рдХреЕрдЯрд▓реЙрдЧ, рдЖрдгрд┐ EXPLAIN.
git checkout lesson-06-indexes