ЁЯзСтАНЁЯТ╗ рдзрдбрд╛ 17 тАФ Code рдордзреВрди database
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 18 рдкреИрдХреА рдзрдбрд╛ 17 ┬╖ рдорд╛рдЧреАрд▓: lesson-16-replication-failover ┬╖ рдкреБрдвреАрд▓: lesson-18-oltp-olap
рднрд╛рдЧ 3 тАФ рдЕрдзрд┐рдХ рдЦреЛрд▓рд╛рдд. рдзрдбреЗ 01тАУ12 рдиреА рд░реЗрдХреЙрд░реНрдб рд░реВрдо рдмрд╛рдВрдзрд▓реА рдЖрдгрд┐ рдЪрд╛рд▓рд╡рд▓реА. рдзрдбреЗ 13тАУ18 рд╣реЗ interviews рдЖрдгрд┐ incidents рдордзреНрдпреЗ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдЬрд╛рдгрд╛рд░реЗ рд╡рд┐рд╖рдп рдЖрд╣реЗрдд тАФ рдкреНрд░рддреНрдпреЗрдХ рддреНрдпрд╛рдЪ
school.dbрд╡рд░ рдкреНрд░рддреНрдпрдХреНрд╖ рдЪрд╛рд▓рддреЛ.
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ17, рдЖрдгрд┐ db/demo.py рдордзрд▓реЗ appcode(): 2,000 inserts рдПрдХреЗрдХ рдХрд░реВрди commit
рд╡рд┐рд░реБрджреНрдз рдПрдХрд╛рдЪ transaction рдордзреНрдпреЗ, рдЖрдгрд┐ database is locked рд▓рд╛ рднреЗрдЯрдгрд╛рд░рд╛ рдЖрдгрд┐ exponential backoff
рд╕рд╣ рддрд┐рд╕рд▒реНрдпрд╛ рдкреНрд░рдпрддреНрдирд╛рдд рдпрд╢рд╕реНрд╡реА рд╣реЛрдгрд╛рд░рд╛ рдПрдХ write.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдПрдХ рдорджрддрдиреАрд╕ рд╡рд░реНрдЧрд╛рддреВрди рд░реЗрдХреЙрд░реНрдб рд░реВрдордХрдбреЗ forms рдШреЗрдКрди рдЬрд╛рддреЗ. рддреА рдЦреЛрд▓реАрдкрд░реНрдпрдВрдд рдЪрд╛рд▓рдд рдЧреЗрд▓реА, рдПрдХ form рджрд┐рд▓рд╛, рд╢рд┐рдХреНрдХреНрдпрд╛рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рд┐рд▓реА, рдЖрдгрд┐ рдкрд░рдд рдЖрд▓реА тАФ 2,000 рд╡реЗрд│рд╛ тАФ рддрд░ рджрд┐рд╡рд╕ рд╕рдВрдкрддреЛ. рдЬрд░ рддреА 2,000 forms рдЪрд╛ рдПрдХ рдЦреЛрдХрд╛ рдШреЗрдКрди рдЧреЗрд▓реА рдЖрдгрд┐ рдПрдХ рд╢рд┐рдХреНрдХрд╛ рдШреЗрддрд▓рд╛, рддрд░ рдХреНрд╖рдгрднрд░ рд▓рд╛рдЧрддреЛ. рдкреНрд░рддреНрдпреЗрдХ COMMIT рдореНрд╣рдгрдЬреЗ рдЦреЛрд▓реАрдкрд░реНрдпрдВрддрдЪреА рдПрдХ рдлреЗрд░реА.
рдХрдзреА рдХрдзреА рджреБрд╕рд░рд╛ рдХрд╛рд░рдХреВрди рдЖрдд рдЕрд╕рд▓реНрдпрд╛рдореБрд│реЗ рдЦреЛрд▓реАрдЪреЗ рджрд╛рд░ рдХреНрд╖рдгрднрд░ рдмрдВрдж рдЕрд╕рддреЗ. рд╢рд╣рд╛рдгреА рдорджрддрдиреАрд╕ рдереЛрдбреА рдерд╛рдВрдмрддреЗ, рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрди рдХрд░рддреЗ, рдЖрдгрдЦреА рдереЛрдбреА рдерд╛рдВрдмрддреЗ, рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрди рдХрд░рддреЗ тАФ рдЖрдгрд┐ рдХрд╛рдпрдо рджрд╛рд░ рдареЛрдард╛рд╡рдд рд░рд╛рд╣рдгреНрдпрд╛рдРрд╡рдЬреА рдХрд╛рд╣реА рдкреНрд░рдпрддреНрдирд╛рдВрдирдВрддрд░ рдирдореНрд░рдкрдгреЗ рдерд╛рдВрдмрддреЗ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
req["ЁЯМР request"] --> pool["ЁЯЪ░ pool: borrow a connection"]
pool --> tx["with conn: BEGIN тАж COMMIT<br/>parameters (?) only"]
tx --> ok["тЬЕ return the connection"]
tx -. "database is locked" .-> retry["тП│ retry: 50 тЖТ 100 тЖТ 200 ms, then give up"]
retry --> tx
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/database/lesson-diagrams.html#l17
тЭУ рдХрд╛рдп
- Connection pool тАФ рдкреНрд░рддреНрдпреЗрдХ request рд╕рд╛рдареА рдирд╡реЗ connection рдЙрдШрдбрдгреНрдпрд╛рдРрд╡рдЬреА connections рдЙрд╕рдиреЗ рдШреНрдпрд╛ рдЖрдгрд┐ рдкрд░рдд рдХрд░рд╛ (рдзрдбрд╛ 10). рддреЗ рдиреЗрд╣рдореА рдкрд░рдд рдХрд░рд╛ тАФ рдЧрд│рд▓реЗрд▓реЗ (leaked) connection pool рд░рд┐рдХрд╛рдорд╛ рдХрд░рддреЗ.
- рдХрд╛рдорд╛рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдПрдХрдХрд╛рд╕рд╛рдареА рдПрдХ рдЫреЛрдЯреЗ transaction тАФ Python рдордзрд▓реЗ
with conn:рд╢реЗрд╡рдЯреА commit рдХрд░рддреЗ рдЖрдгрд┐ рдХреЛрдгрддреНрдпрд╛рд╣реА exception рд╡рд░ rollback рдХрд░рддреЗ (рдзрдбрд╛ 04). User рдХрд┐рдВрд╡рд╛ network call рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рдд рдЕрд╕рддрд╛рдирд╛ transaction рдХрдзреАрдЪ рдЙрдШрдбреЗ рдареЗрд╡реВ рдирдХрд╛. - Parameters, рдиреЗрд╣рдореА (рдзрдбрд╛ 13).
- Batching тАФ рдПрдХрд╛рдЪ transaction рдордзреНрдпреЗ
executemany; рдореЛрдареНрдпрд╛ imports рд╕рд╛рдареА bulk loaders (Postgres рдордзреНрдпреЗCOPY). - Backoff рд╕рд╣ retries тАФ рдлрдХреНрдд рддрд╛рддреНрдкреБрд░рддреНрдпрд╛ errors рд╡рд░ retry рдХрд░рд╛ (locked, deadlock victim, connection reset), рдлрдХреНрдд рд╕рдВрдкреВрд░реНрдг transactions рдХрд┐рдВрд╡рд╛ idempotent writes, рдЖрдгрд┐ рдПрдХрд╛ рдорд░реНрдпрд╛рджреЗрд╕рд╣.
- ORMs (SQLAlchemy, Django, ActiveRecord, Prisma) тАФ objects рдирд╛ rows рд╢реА рдЬреЛрдбрддрд╛рдд рдЖрдгрд┐ рддреБрдордЪреНрдпрд╛рд╕рд╛рдареА SQL рдЖрдгрд┐ parameters рд▓рд┐рд╣рд┐рддрд╛рдд. рддреНрдпрд╛рдВрдЪреНрдпрд╛рдореБрд│реЗ N+1 рд╕реЛрдкреЗ рд╣реЛрддреЗ (рдзрдбрд╛ 12): query count log рдХрд░рд╛.
ЁЯдФ рдХрд╛
рдмрд╣реБрддреЗрдХ "database рд╣рд│реВ рдЖрд╣реЗ" tickets рдореНрд╣рдгрдЬреЗ рдЦрд░реЗрддрд░ "app database рд╢реА рд╡рд╛рдИрдЯ рдкрджреНрдзрддреАрдиреЗ рдмреЛрд▓рддреЗ": рдЦреВрдк commits, рдЦреВрдк connections, рдЦреВрдк round trips, рдЖрдгрд┐ lock рд╕рд╛рдареА рдХреЛрдгрддреАрдЪ рдпреЛрдЬрдирд╛ рдирд╛рд╣реА.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
db/demo.py рдордзрд▓реЗ appcode() тАФ рддреЗ рджреБрд╕рд▒реНрдпрд╛ connection рдордзреВрди write lock рдзрд░реВрди
рдареЗрд╡рддреЗ, рддреНрдпрд╛рдореБрд│реЗ retry loop рд▓рд╛ рдЦрд░рд╛ database is locked рднреЗрдЯрддреЛ, рдордЧ рддреЗ lock рд╕реЛрдбрддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 db/demo.py appcode
python3 - <<'EOF'
import sqlite3, time
c = sqlite3.connect(":memory:"); c.execute("CREATE TABLE t (x)")
for n in (100, 1000, 5000):
t = time.perf_counter()
with c: c.executemany("INSERT INTO t VALUES (?)", ((i,) for i in range(n)))
print(n, "rows in one transaction:", round((time.perf_counter() - t) * 1000, 2), "ms")
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
рдХрд╛рд╣реАрд╕реЗ рдЕрд╕реЗ commit per row 513 ms ┬╖ one transaction 1 ms (рддреБрдордЪреЗ рдЖрдХрдбреЗ рд╡реЗрдЧрд│реЗ рдЕрд╕рддреАрд▓;
рдЧреБрдгреЛрддреНрддрд░ рд╣рд╛рдЪ рдзрдбрд╛ рдЖрд╣реЗ), рдордЧ attempt 1 тАж locked, attempt 2 тАж locked, attempt 3: done.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рдПрдХрджрд╛рдЪ commit рдХрд░реВрди рддреБрдореНрд╣реА writes рд╢реЗрдХрдбреЛ рдкрдЯ рдЬрд▓рдж рдХрд░реВ рд╢рдХрддрд╛, рдЖрдгрд┐ рдереЛрдбрд╛ рд╡реЗрд│ рдХреБрд▓реВрдкрдмрдВрдж рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдЦреЛрд▓реАрдд app рдЕрдбрдХреВрди рди рдкрдбрддрд╛ рдХрд┐рдВрд╡рд╛ рддрд┐рдЪреНрдпрд╛рд╡рд░ рдШрд╛рд╡ рди рдШрд╛рд▓рддрд╛ рдЯрд┐рдХрд╡реВ рд╢рдХрддрд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- loop рдЪреНрдпрд╛ рдЖрдд рдкреНрд░рддреНрдпреЗрдХ row рд╡рд░ autocommit
- рдкреНрд░рддреНрдпреЗрдХ query рд╕рд╛рдареА рдирд╡реЗ connection рдЙрдШрдбрдгреЗ
- HTTP call рдХрд┐рдВрд╡рд╛ user input рджрд░рдореНрдпрд╛рди рдЙрдШрдбреЗ рд░рд╛рд╣рд┐рд▓реЗрд▓реЗ transaction
- рдкреНрд░рддреНрдпрдХреНрд╖рд╛рдд рдпрд╢рд╕реНрд╡реА рдЭрд╛рд▓реЗрд▓реНрдпрд╛ non-idempotent write рд╡рд░ retry (рджреБрд╣реЗрд░реА charges)
- ORM рд╡рд░ рдбреЛрд│реЗ рдЭрд╛рдХреВрди рд╡рд┐рд╢реНрд╡рд╛рд╕ тАФ рддреЗ рдкрд╛рдард╡рддреЗ рддреЛ SQL рд╡рд╛рдЪрд╛
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: pool sizes, transaction scope, retry policy рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ request рдорд╛рдЧрдЪреЗ query counts рд╣реЗрдЪ reviewers рдкреНрд░рддреНрдпреЗрдХ service рдЪреНрдпрд╛ data layer рдордзреНрдпреЗ рддрдкрд╛рд╕рддрд╛рдд.
тПня╕П рдкреБрдвреЗ
git checkout lesson-18-oltp-olap тАФ рдореЛрдареЗ reports рдХреБрдареЗ рдЪрд╛рд▓рд╡рд╛рдпрдЪреЗ.