Changes between Version 4 and Version 5 of Transakcii


Ignore:
Timestamp:
04/06/26 13:23:36 (5 days ago)
Author:
213192
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Transakcii

    v4 v5  
    11== Трансакции
    22
     3Во системи со повеќе корисници како што е Transfermarkt базата на податоци, истовременото извршување на операции може да доведе до неконзистентни податоци и грешки. Затоа се користат трансакции, механизми за заклучување и Multi-Version Concurrency Control (MVCC), кои обезбедуваат сигурност, изолација и висока конкурентност. Во овој дел се анализираат овие концепти преку практични и реални сценарија.
     4
    35Трансакција е логичка целина од повеќе операции над базата на податоци. Тие располагаат со повеќе својства (ACID својства):
    46
     
    1113* трајност: најважно од се е промените да се запишат и зачуваат по извршувањето. За тоа PostgreSQL користи WAL (ќе го споменеме понатаму). Ако серверот се рестартира, податоците нема да бидат изгубени по извршена трансакција.
    1214
     15Сценарио: трансфер на играч
     16При трансфер на играч, потребно е да се ажурираат повеќе табели истовремено: буџетот на клубот, информациите за играчот и историјата на трансфери. Овие операции мора да се извршат атомично за да се избегне неконзистентност.
     17{{{
     18BEGIN;
     19 
     20SELECT budget 
     21FROM clubs 
     22WHERE club_id = 10 
     23FOR UPDATE;
     24 
     25UPDATE clubs
     26SET budget = budget - 5000000
     27WHERE club_id = 10;
     28 
     29UPDATE players
     30SET club_id = 10
     31WHERE player_id = 65;
     32 
     33INSERT INTO transfers(player_id, from_club, to_club, amount)
     34VALUES (65, 5, 10, 5000000);
     35 
     36COMMIT;
     37}}}
     38Прво се заклучува редот за клубот за да се спречи истовремено менување, буџетот се намалува, играчот се префрла во нов клуб, се запишува трансфер. Доколку било која операција не успее, трансакцијата ќе се поништи (ROLLBACK)
     39{{{
     40BEGIN;
     41 
     42UPDATE clubs
     43SET budget = budget - 100000000
     44WHERE club_id = 10;
     45 
     46ROLLBACK;
     47}}}
     48Ова спречува неконзистентност на базата.
     49
     50=== Конкурентност
     51
     52Lost update проблемот се јавува кога две трансакции истовремено читаат и ажурираат ист податок.
     53{{{
     54Session 1:
     55
     56BEGIN;
     57SELECT budget FROM clubs WHERE club_id = 10;
     58}}}
     59{{{
     60BEGIN;
     61SELECT budget FROM clubs WHERE club_id = 10;
     62UPDATE clubs SET budget = 5000000 WHERE club_id = 10;
     63COMMIT;
     64}}}
     65{{{
     66UPDATE clubs SET budget = 7000000 WHERE club_id = 10;
     67COMMIT;
     68}}}
     69Вредноста од Session 2 се губи → lost update. Како да се спречи ова? Со Row-Level Locking, поточно со FOR UPDATE кој го заклучува редот.
     70{{{
     71BEGIN;
     72 
     73SELECT budget 
     74FROM clubs 
     75WHERE club_id = 10 
     76FOR UPDATE;
     77 
     78UPDATE clubs
     79SET budget = budget - 5000000
     80WHERE club_id = 10;
     81 
     82COMMIT;
     83}}}
     84
    1385=== Изолациони нивоа
    1486
     
    2597READ COMMITTED vs SERIALIZABLE
    2698
    27 {{{
    28 BEGIN;
    29 
    30  
    31 
    32 SELECT highest_market_value_in_eur
     99Доколку имаме сценарио дека еден клуб не смее да има повеќе од 5 играчи кои имаат под 18 години(младинци) и ја имаме следната трансакција:
     100{{{
     101-- Transaction 1
     102BEGIN;
     103
     104SELECT COUNT(*)
    33105FROM players
    34 WHERE player_id = 65;
    35 UPDATE players
    36 SET highest_market_value_in_eur = 7000000
    37 WHERE player_id = 65;
    38 
    39 COMMIT;
    40 }}}
    41 {{{
    42 SELECT highest_market_value_in_eur
     106WHERE club_id = 10 AND age < 18;
     107
     108-- резултат = 4
     109
     110INSERT INTO players(name, age, club_id)
     111VALUES ('Young Player 1', 17, 10);
     112
     113COMMIT;
     114}}}
     115{{{
     116-- Transaction 2
     117BEGIN;
     118
     119SELECT COUNT(*)
    43120FROM players
    44 WHERE player_id = 65;
    45 
    46 COMMIT;
    47 }}}
    48 
    49 Истата трансакција гледа различна вредност, ова е дозволено во READ COMMITTED
    50 
    51 {{{
    52 BEGIN ISOLATION LEVEL SERIALIZABLE;
    53 
    54 SELECT highest_market_value_in_eur
    55 FROM players
    56 WHERE player_id = 65;
    57 
    58 UPDATE players 
    59 SET highest_market_value_in_eur = 70000000
    60 WHERE player_id = 65; 
    61 
    62 COMMIT; 
    63 
    64 SELECT highest_market_value_in_eur
    65 FROM players
    66 WHERE player_id = 65;
    67 
    68 COMMIT;
    69 }}}
    70 
    71 Serializable нема non-repeatable read, конзистентност на ниво на трансакција.
     121WHERE club_id = 10 AND age < 18;
     122
     123-- резултат = 4
     124
     125INSERT INTO players(name, age, club_id)
     126VALUES ('Young Player 2', 17, 10);
     127
     128COMMIT;
     129}}}
     130На крај ќе имаме 6 играчи со што constraint-от е прекршен. Ова се нарекува write skew проблем, кој не може да се спречи со READ COMMITTED изолација. Двете трансакции читаат валидна состојба, но поради паралелно извршување, системот завршува во неконзистентна состојба. Решение за оваа ситуација е :
     131{{{
     132SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
     133}}}
     134SERIALIZABLE изолацијата гарантира дека ваквите аномалии нема да се појават, но по цена на намалени перформанси.
    72135
    73136=== Deadlocks
     
    103166Deadlock состојбите претставуваат сериозен предизвик во системи со висока конкурентност. PostgreSQL користи автоматска детекција на deadlock, при што една од трансакциите се прекинува за да се избегне застој на системот. Примената на конзистентен редослед на заклучување и краткотрајни трансакции значително го намалува ризикот од вакви ситуации.
    104167
    105 === Locks и MVCC во PostgreSQL
    106 
    107 Во системи со повеќе истовремени корисници, базата на податоци мора да обезбеди конзистентност и изолација на податоците, без притоа да се жртвуваат перформансите. PostgreSQL го решава овој проблем преку комбинација на механизми за заклучување (locking) и Multi-Version Concurrency Control (MVCC).
    108 
    109 Во овој дел се прикажува разликата помеѓу table-level locking, row-level locking и MVCC, со практични примери кои покажуваат како различните пристапи влијаат врз конкурентноста, блокирањето и видливоста на податоците помеѓу трансакции.
    110 
    111 Table-level locking
    112 
    113 * целата табела е заклучена
    114 * други трансакции чекаат, дури и ако работат на друг ред
    115 * многу лоша конкурентност
    116 
    117 {{{
    118 BEGIN;
    119 
    120 LOCK TABLE players IN ACCESS EXCLUSIVE MODE;
    121 
    122 -- табелата е целосно заклучена
    123 
    124 SELECT * FROM players; (ACCESS EXCLUSIVE е најсилен lock)
    125 }}}
    126 
    127 Row-level locking
    128 
    129 * многу подобра верзија од table-level locking
    130 * се заклучува само конкретниот ред, другите редови се слободни
    131 
    132 {{{
    133 BEGIN;
    134 
    135 SELECT * FROM players WHERE player_id = 65 FOR UPDATE;
    136 
    137 -- само редот со id=1 е заклучен
    138 
    139 SELECT * FROM players WHERE player_id = 80;
    140 
    141 -- работи нормално
    142 
    143 UPDATE players SET highest_market_value_in_eur = highest_market_value_in_eur - 100 WHERE player_id = 65;
    144 
    145 -- чека, редот е заклучен
    146 }}}
    147 
    148 MVCC(Multi-Version Concurrency Control)
    149 
    150 * наместо locks, PostgreSQL креира нови верзии на редиците (помалку блокирања)
    151 
     168=== MVCC
     169Во системи со повеќе истовремени корисници, класичните механизми за заклучување (locking) можат да доведат до блокирање и намалени перформанси. PostgreSQL го решава овој проблем преку Multi-Version Concurrency Control (MVCC), кој овозможува читање на податоци без блокирање, преку одржување на повеќе верзии на редиците. Наместо да ги заклучува податоците, системот создава нови верзии при секоја промена, додека старите верзии остануваат достапни за други трансакции.
     170
     171Сценарио 1: Read without blocking - Во класичен locking систем, кога една трансакција ажурира податок, другите трансакции мора да чекаат. Со MVCC, читањето не се блокира, што овозможува висока конкурентност.
    152172{{{
    153173-- Session 1
     
    155175
    156176UPDATE players
    157 SET market_value_in_eur = market_value_in_eur - 5000000
    158 WHERE player_id = 65;
    159 
    160 -- трансакцијата е започната, но не е направен COMMIT
    161 }}}
    162 
     177SET market_value_in_eur = 12000000
     178WHERE player_id = 65;
     179}}}
    163180{{{
    164181-- Session 2
     
    166183FROM players
    167184WHERE player_id = 65;
    168 -- Session 2 ја гледа старата вредност
    169 }}}
    170 
    171 {{{
    172 -- Session 1
    173 COMMIT;
    174 }}}
    175 
     185}}}
     186Иако Session 1 ја менува вредноста, Session 2 ја гледа старата вредност. Причината е што промената сè уште не е commit-ирана, па MVCC обезбедува читање од претходната верзија на редицата. На овој начин се избегнува блокирање и се овозможува паралелно извршување на операции.
     187
     188Сценарио 2: Concurrent updates без блокирање - MVCC овозможува повеќе трансакции да работат паралелно, дури и кога ажурираат различни редови.
     189{{{
     190-- Session 1
     191BEGIN;
     192UPDATE players
     193SET market_value_in_eur = market_value_in_eur + 2000000
     194WHERE player_id = 65;
     195}}}
    176196{{{
    177197-- Session 2
    178 SELECT market_value_in_eur
    179 FROM players
    180 WHERE player_id = 65;
    181 -- сега Session 2 ја гледа новата вредност
    182 }}}
    183 
    184 MVCC е одличен бидејќи нема блокирање на SELECT операции, нема dirty reads и има висока конкурентност.
     198BEGIN;
     199UPDATE players
     200SET market_value_in_eur = market_value_in_eur + 3000000
     201WHERE player_id = 80;
     202}}}
     203Бидејќи трансакциите работат со различни редови, тие не се блокираат меѓусебно. MVCC овозможува паралелно извршување, што значително ги подобрува перформансите во системи со голем број корисници.
     204
     205Сценарио 3: Update conflict - Иако MVCC дозволува паралелно читање, конфликт може да настане кога две трансакции се обидуваат да ажурираат ист ред.
     206{{{
     207-- Session 1
     208BEGIN;
     209UPDATE players
     210SET market_value_in_eur = 15000000
     211WHERE player_id = 65;
     212}}}
     213{{{
     214-- Session 2
     215BEGIN;
     216UPDATE players
     217SET market_value_in_eur = 20000000
     218WHERE player_id = 65;
     219}}}
     220Во овој случај, една од трансакциите ќе мора да чека додека другата не заврши. MVCC не ги елиминира сите конфликти, туку овозможува баланс помеѓу конкурентност и конзистентност.
     221
     222MVCC vs Locking: Главната разлика помеѓу MVCC и класичното заклучување е во тоа што MVCC дозволува читање без блокирање, додека locking пристапот блокира операции. MVCC обезбедува подобра конкурентност, но бара дополнителна меморија за чување на повеќе верзии.