ЁЯй║ рдзрдбрд╛ 12 тАФ Performance рдЖрдгрд┐ operations: рд░реЗрдХреЙрд░реНрдб рд░реВрдо on call
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 18 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреАрд▓: lesson-11-nosql-other-rooms ┬╖ рдкреБрдвреАрд▓: lesson-13-security
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕, рдЖрдгрд┐ рд╢реЗрд╡рдЯрдЪрд╛ рдЯрдкреНрдкрд╛: N+1 рдЪрд╛ рд╕рд╛рдкрд│рд╛, slow-query log, рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ metrics, рдЖрдгрд┐ рдЗрддрд░ рд▓реЛрдХ рдЬреНрдпрд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЖрд╣реЗрдд рдЕрд╢рд╛ рд░реЗрдХреЙрд░реНрдб рд░реВрдорд╕рд╛рдареА on-call рдЪреЗрдХрд▓рд┐рд╕реНрдЯ.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдПрдХрд╛ report рд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдЖрдгрд┐ рддреНрдпрд╛рдЪреНрдпрд╛ рд╢реНрд░реЗрдгреА рд╣рд╡реНрдпрд╛ рдЖрд╣реЗрдд. рдЖрд│рд╢реА рдкрджреНрдзрддреАрдд
рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓рд╛рд▓рд╛ рдпрд╛рджреАрд╕рд╛рдареА рдПрдХ рдкреНрд░рд╢реНрди, рдордЧ рдкреНрд░рддреНрдпреЗрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рд╕рд╛рдареА рдПрдХ рдкреНрд░рд╢реНрди
рдкрд╛рдард╡рд▓рд╛ рдЬрд╛рддреЛ тАФ рдкрд╛рдЪ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рдВрд╕рд╛рдареА рд╕рд╣рд╛ рдлреЗрд▒реНрдпрд╛, рд╣рдЬрд╛рд░рд╛рд╕рд╛рдареА рдПрдХ рд╣рдЬрд╛рд░ рдПрдХ рдлреЗрд▒реНрдпрд╛.
рд╣реЗрдЪ N+1, рдЖрдгрд┐ рдЬрдЧрд╛рддрд▓реЗ рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдорд╛рдиреНрдп рд╣рд│реВ page рд╣реЗрдЪ рдЖрд╣реЗ. рдЙрдкрд╛рдп рдореНрд╣рдгрдЬреЗ рдПрдХрдЪ
рдлреЗрд░реА: рдПрдХ JOIN (рдХрд┐рдВрд╡рд╛ рдПрдХ WHERE id IN (тАж)).
рдЕрд╢рд╛ рдЧреЛрд╖реНрдЯреА users рдЪреНрдпрд╛ рдЖрдзреА рдХрд╢рд╛ рд╢реЛрдзрд╛рдпрдЪреНрдпрд╛? рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓ рдПрдХ
рд╣рд│реВ-рдкреНрд░рд╢реНрдирд╛рдВрдЪреА рдиреЛрдВрджрд╡рд╣реА ЁЯй║ рдареЗрд╡рддреЗ: N milliseconds рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рд╡реЗрд│ рдШреЗрддрд▓реЗрд▓рд╛
рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрди, рддреНрдпрд╛рдЪреНрдпрд╛ рдорд╛рд░реНрдЧрд╛рд╕рд╣ (EXPLAIN). рддреА рджрд░ рдЖрдард╡рдбреНрдпрд╛рд▓рд╛ рд╡рд╛рдЪрд╛; рд╡рд░рдЪреЗ рджрд╣рд╛
рдореНрд╣рдгрдЬреЗ рддреБрдордЪреЗ рдкреБрдврдЪреЗ рджрд╣рд╛ рд╕реБрдзрд╛рд░.
рдЖрдгрд┐ рдЦреЛрд▓реА on call рдЕрд╕рддрд╛рдирд╛, "рддреА рдирд┐рд░реЛрдЧреА рдЖрд╣реЗ рдХрд╛?" рдпрд╛рдЪреЗ рдЙрддреНрддрд░ рдПрдХ рдЫреЛрдЯреА рдЪреЗрдХрд▓рд┐рд╕реНрдЯ рдХреЛрдгрддреНрдпрд╛рд╣реА dashboard рдлреЗрд░реАрдкреЗрдХреНрд╖рд╛ рд▓рд╡рдХрд░ рджреЗрддреЗ:
- connections рдорд░реНрдпрд╛рджреЗрдЬрд╡рд│? ┬╖ replication lag? ┬╖ disk рдЖрдгрд┐ log рдЪреА рд╡рд╛рдв?
- lock waits рдЖрдгрд┐ deadlocks? ┬╖ рдпрд╛ рдЖрдард╡рдбреНрдпрд╛рддрд▓реНрдпрд╛ рд╕рд░реНрд╡рд╛рдд рд╣рд│реВ рджрд╣рд╛ queries?
- рд╢реЗрд╡рдЯрдЪрд╛ restore drill рдХрдзреА рдЭрд╛рд▓рд╛?
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
n1["ЁЯРв N+1<br/>SELECT students; then SELECT grades WHERE student_id = ? ├Ч N"]
one["ЁЯРЗ one JOIN<br/>SELECT s.name, COUNT(g.id) тАж LEFT JOIN тАж GROUP BY s.id"]
log["ЁЯй║ slow-query log<br/>every query > N ms, with its plan"]
dash["ЁЯУК QPS ┬╖ p95 latency ┬╖ error rate ┬╖ cache hit rate ┬╖ connections ┬╖ lag ┬╖ disk"]
n1 -->|"1 rewrite"| one
log -->|"2 top ten weekly"| one
dash -->|"3 alert on"| log
тЭУ рдХрд╛рдп
- N+1: queries рдЪрд╛ loop.
JOIN,IN (тАж), рдХрд┐рдВрд╡рд╛ ORM рдЪреЗ eager loading (select_related,includes,joinedload) рд╡рд╛рдкрд░реВрди рд╕реБрдзрд╛рд░рд╛. - Slow-query log:
log_min_duration_statement(Postgres), slow log (MySQL); code рдордзреНрдпреЗ, рдкреНрд░рддреНрдпреЗрдХ query рдЪреА рд╡реЗрд│ рдореЛрдЬрд╛ рдЖрдгрд┐ рдорд░реНрдпрд╛рджреЗрдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЕрд╕реЗрд▓ рддрд░ request id рд╕рд╣ log рдХрд░рд╛ (API school L12). - Metrics: queries per second, рдкреНрд░рддреНрдпреЗрдХ query family рд╕рд╛рдареА p95/p99 latency, error rate, cache hit ratio (buffer cache!), рд╡рд╛рдкрд░рд▓реЗрд▓реЗ connections рд╡рд┐рд░реБрджреНрдз max, replication lag, рдореЛрдХрд│реА disk, WAL size, lock waits, deadlocks. рдЬреНрдпрд╛рдВрдЪреНрдпрд╛рд╕рд╛рдареА рдорд╛рдгрд╕рд╛рд▓рд╛ page рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧрддреЗ рддреНрдпрд╛рдВрдЪреНрдпрд╛рд╡рд░ alert рд▓рд╛рд╡рд╛; рдмрд╛рдХреА dashboard рд╡рд░ рдареЗрд╡рд╛.
- "Database рд╣рд│реВ рдЖрд╣реЗ" рд╕рд╛рдареА рддрдкрд╛рд╕рдгреАрдЪрд╛ рдХреНрд░рдо: рдХрд╛рдп рдмрджрд▓рд▓реЗ (deploy,
data рд╡рд╛рдв)? тЖТ slow-query log тЖТ рд╡рд░рдЪреНрдпрд╛ query рдЪрд╛
EXPLAINтЖТ index рдХрд┐рдВрд╡рд╛ rewrite тЖТ рдкреБрдиреНрд╣рд╛ рдореЛрдЬрд╛. рдордЧ рд╢рд┐рдбреА (рдзрдбрд╛ 10). - рджреЗрдЦрднрд╛рд▓: vacuum/analyze (Postgres), statistics, index bloat, restore drill, credential rotation, version upgrades рдЖрдзреА рдПрдХрд╛ copy рд╡рд░.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг database install рдХрд░реВрди рд╕рдВрдкрдд рдирд╛рд╣реА, рддреЛ рдЪрд╛рд▓рд╡рд╛рд╡рд╛ рд▓рд╛рдЧрддреЛ. рдЬреА team рджрд░ рдЖрдард╡рдбреНрдпрд╛рд▓рд╛ slow log рд╡рд╛рдЪрддреЗ рдЖрдгрд┐ рджрд░ рддрд┐рдорд╛рд╣реАрд▓рд╛ restore drill рдХрд░рддреЗ, рддрд┐рдЪреЗ on-call рдХрдВрдЯрд╛рд│рд╡рд╛рдгреЗ рдЕрд╕рддреЗ; рдЬреА team рджреЛрдиреНрд╣реАрдкреИрдХреА рдХрд╛рд╣реАрдЪ рдХрд░рдд рдирд╛рд╣реА, рддреА рджреЛрдиреНрд╣реА outage рдордзреВрди рд╢рд┐рдХрддреЗ. рдЪреЗрдХрд▓рд┐рд╕реНрдЯ рд╣рд╛рдЪ рд╕рдЧрд│рд╛ рдлрд░рдХ рдЖрд╣реЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
db/demo.py рдордзрд▓реЗ nplus1() loop рдЖрдгрд┐ JOIN рджреЛрдиреНрд╣реА рдЪрд╛рд▓рд╡рддреЗ
рдЖрдгрд┐ рджреЛрдиреНрд╣реАрдЪреА рд╡реЗрд│ рдореЛрдЬрддреЗ. school.db рд╕рд╛рдареА рдЪреЗрдХрд▓рд┐рд╕реНрдЯ рддреБрдореНрд╣реА рд▓рд┐рд╣рд╛рдпрдЪреА рдЖрд╣реЗ тАФ рдЫреЛрдЯреНрдпрд╛
рдЦреЛрд▓реНрдпрд╛рдВрдирд╛рд╣реА рддреЗрдЪ рдкреНрд░рд╢реНрди рд▓рд╛рдЧрддрд╛рдд, рдлрдХреНрдд рд▓рд╣рд╛рди рдкреНрд░рдорд╛рдгрд╛рдд.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛ тАФ capstone
python3 db/demo.py nplus1
python3 - <<'EOF'
import sqlite3, time
c = sqlite3.connect("db/school.db")
# 1) a slow-query log in 6 lines
def q(sql, *a, threshold_ms=0.05):
t=time.perf_counter(); rows=c.execute(sql, a).fetchall(); ms=(time.perf_counter()-t)*1000
if ms > threshold_ms: print(f"ЁЯРв {ms:.3f} ms ┬╖ {sql[:60]} ┬╖ plan: {c.execute('EXPLAIN QUERY PLAN '+sql, a).fetchall()[0][3]}")
return rows
q("SELECT COUNT(*) FROM attendance WHERE day = '2026-03-03'") # a candidate for the log
q("SELECT COUNT(*) FROM attendance WHERE student_id = 4242") # served by lesson 06's index
# 2) the checklist, measured:
print("rows:", c.execute("SELECT COUNT(*) FROM attendance").fetchone()[0], "┬╖ page_size:", c.execute("PRAGMA page_size").fetchone()[0], "┬╖ journal:", c.execute("PRAGMA journal_mode").fetchone()[0])
EOF
# 3) capstone: add a teachers table (L05), a migration for it (L08), an index a new question needs (L06),
# a query that would be N+1 written as one JOIN, and a one-page on-call checklist for school.db.
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
nplus1 рдПрдХрд╛рдЪ рдЙрддреНрддрд░рд╛рд╕рд╛рдареА 6 queries рд╡рд┐рд░реБрджреНрдз 1 рджрд╛рдЦрд╡рддреЗ; рддреБрдордЪрд╛ slow-query log day query SCAN plan рд╕рд╣ рдЫрд╛рдкрддреЛ (index рд╕рд╛рдареА рдЙрдореЗрджрд╡рд╛рд░) рдЖрдгрд┐ index рдЕрд╕рд▓реЗрд▓реНрдпрд╛ student_id query рд╕рд╛рдареА рдЧрдкреНрдк рд░рд╛рд╣рддреЛ. рдЪреЗрдХрд▓рд┐рд╕реНрдЯ рдЦрд▒реНрдпрд╛ file рд╕рд╛рдареА рдЦрд░реЗ рдЖрдХрдбреЗ рдЫрд╛рдкрддреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреБрдореНрд╣реА рд╣рд│реВ рдкреНрд░рд╢реНрди рд╢реЛрдзреВ рд╢рдХрддрд╛, рддреНрдпрд╛рдЪрд╛ рдорд╛рд░реНрдЧ рд╡рд╛рдЪреВ рд╢рдХрддрд╛, рдПрдХрд╛ JOIN рдиреЗ рдХрд┐рдВрд╡рд╛ рдПрдХрд╛ index рдиреЗ рддреЛ рд╕реБрдзрд╛рд░реВ рд╢рдХрддрд╛, рдЖрдгрд┐ рдЦреЛрд▓реА рдирд┐рд░реЛрдЧреА рдЖрд╣реЗ рдХрд╛ рд╣реЗ тАФ рдЖрдХрдбреНрдпрд╛рдВрд╕рд╣ тАФ рд╕рд╛рдВрдЧреВ рд╢рдХрддрд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рд╕реБрдВрджрд░ code рдорд╛рдЧреЗ N+1 рд▓рдкрд╡рдгрд╛рд░реЗ ORM loops тАФ рдкреНрд░рддреНрдпреЗрдХ request рдорд╛рдЧреЗ query count log рдХрд░рд╛
- рдкреНрд░рддреНрдпреЗрдХ рдЧреЛрд╖реНрдЯреАрд╡рд░ alert (рдХрд┐рдВрд╡рд╛ рдХрд╢рд╛рд╡рд░рдЪ рдирд╛рд╣реА) тАФ рдорд╛рдгрд╕рд╛рдиреЗ рдЖрддреНрддрд╛ рдХреГрддреА рдХрд░рд╛рд╡реА рдЕрд╢рд╛ рдЧреЛрд╖реНрдЯреАрдВрд╡рд░рдЪ page рдХрд░рд╛
- рдЕрдВрджрд╛рдЬрд╛рдиреЗ tuning тАФ рдЖрдзреА рдиреЗрд╣рдореА slow log рдЖрдгрд┐
EXPLAIN - "рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА" рдореНрд╣рдгреВрди restore drill рд╡рд┐рд╕рд░рдгреЗ
- copy рд╡рд░ рд╕рд░рд╛рд╡ рди рдХрд░рддрд╛ рдЪрд╛рд▓реВ рдЦреЛрд▓реАрд╡рд░ database version upgrade рдХрд░рдгреЗ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: database on call рдЬрд╛рдгреНрдпрд╛рдЖрдзреА reviewers рд╣реАрдЪ рдЪреЗрдХрд▓рд┐рд╕реНрдЯ рд╡рд╛рдкрд░рддрд╛рдд: slow log рдЪрд╛рд▓реВ, p95 рдЖрдгрд┐ lag рдЕрд╕рд▓реЗрд▓реЗ dashboards, connection limits рдЖрдгрд┐ pooling, drill рдЪреНрдпрд╛ рддрд╛рд░рдЦреЗрд╕рд╣ backups, CI рдордзреНрдпреЗ migrations. рдПрдХ рдЪреБрдХрд▓реЗ рддрд░реА рддреЗрдЪ incident рдмрдирддреЗ.
ЁЯОУ рд░реЗрдХреЙрд░реНрдб рд░реВрдо рдЖрддрд╛ рддреБрдордЪреА тАФ рднрд╛рдЧ 3 рдЕрдзрд┐рдХ рдЦреЛрд▓рд╛рдд рдЬрд╛рддреЛ
рдЦреЛрд▓реА рдЪрд╛рд▓реВ рдЖрд╣реЗ. рднрд╛рдЧ 3 (рдзрдбреЗ 13тАУ18) interviews рдЖрдгрд┐ incidents рдордзреНрдпреЗ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдЬрд╛рдгрд╛рд░реЗ рдкреНрд░рд╢реНрди рдЙрдШрдбрддреЛ:
git checkout lesson-13-security.
рддреБрдореНрд╣реА рдХреБрдареВрди рдХреБрдареЗ рдЖрд▓рд╛рдд
рдЪрд┐рдХрдЯ рдЪрд┐рдареНрдареНрдпрд╛ тЖТ рд░реЗрдХреЙрд░реНрдб рд░реВрдо тЖТ рдиреЛрдВрджрд╡рд╣реНрдпрд╛ рдЖрдгрд┐ keys тЖТ рдЕрднрд┐рд▓реЗрдЦрдкрд╛рд▓рд╛рд▓рд╛ рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рдгреЗ тЖТ рдкреЗрдиреНрд╕рд┐рд▓рдордзрд▓реА рдиреЛрдВрджрд╡рд╣реА тЖТ рдПрдХ рддрдереНрдп, рдПрдХ рдЬрд╛рдЧрд╛ тЖТ рдХрд╛рд░реНрдб рдХреЕрдЯрд▓реЙрдЧ тЖТ рджреЛрди рдХрд╛рд░рдХреВрди, рдПрдХ рдиреЛрдВрджрд╡рд╣реА тЖТ рдЪрд╛рд▓реВ рдЕрд╕рддрд╛рдирд╛рдЪ рдиреВрддрдиреАрдХрд░рдг тЖТ рдЖрдЧреАрдкрд╛рд╕реВрди рд╕реБрд░рдХреНрд╖рд┐рдд рдкреНрд░рдд тЖТ рдЕрдзрд┐рдХ рдХрд╛рд░рдХреВрди, рдЕрдзрд┐рдХ рдЦреЛрд▓реНрдпрд╛ тЖТ рдЗрддрд░ рдЦреЛрд▓реНрдпрд╛ тЖТ on call. рддреБрдореНрд╣реА рдлрдХреНрдд databases рд╢рд┐рдХрд▓реНрдпрд╛ рдирд╛рд╣реАрдд тАФ рддреБрдореНрд╣реА рдПрдХ рдЪрд╛рд▓рд╡рддрд╛. ЁЯЧДя╕ПЁЯОУ
рд╢рд╛рд│реЗрддрд▓реЗ рдкреБрдврдЪреЗ рджрд░рд╡рд╛рдЬреЗ: API рд╢рд╛рд│рд╛ рдпрд╛ рдЦреЛрд▓реАрд╕рдореЛрд░ рдПрдХ counter рдареЗрд╡рддреЗ; VectorDB рд╢рд╛рд│рд╛ рд╢реЗрдЬрд╛рд░рдЪреЗ рдЕрд░реНрдерд╛рдЪреЗ рд╕рднрд╛рдЧреГрд╣ рдЙрдШрдбрддреЗ.
git checkout main
python3 db/demo.py # one last run, for fun