Keletas teiginiu: 1. Serializable visada bus letesnis nei kiti isolation leveliai del vienos paprastos priezasties - DBVS turi atlikti papildomus veiksmus tam, kad serializuoti transakcijas. O papildomi veiksmai reikalauja laiko, galbut labai labai mazai, bet visvien jie jo prideda, ne atima. 2. Zodziai serializable ir performance yra antonimai, ypac high concurency aplinkoje. 3. Zodziai deadlock ir performance yra antonimai, cia net nematau reikalo kazka bandyti spresti deadlocku pagalba, tai savizudybe. 4. Serializable apsaugo nuo phantomu. Phantomai is principo neimanomi dirbant su vienu irasu. Phantomas gali atsirasti tik tada, kai tas pats selectas kartojamas vienoj transakcijoj bent 2 kartus, + to selecto atrankos kriterijai leidzia jam grazinti daugiau nei viena irasa (select * from tbl where pk_value = :constant, negali grazinti daugiau nei vieno iraso). Kadangi phantomas cia niekaip negali atsirasti, vadinasi, norint pagerint greitaveika(!), nera reikalo naudoti serial transakciju. Prie viso to anot MySQL dokumentacijos (nepykit jei nepataikiau i versija, ziurejau pirma pasitaikiusia): http://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-model.html#innodb-lock-modes cia ziuriu apacioj i lentele lock type compatibility matrix, noriu atkreipti demesi i tai, kad S ir S kombinacija yra compatible. http://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-model.html#innodb-locks-set cia skaitau SELECT ... FROM is a consistent read, reading a snapshot of the database and setting no locks unless the transaction isolation level is set to SERIALIZABLE. For SERIALIZABLE level, the search sets shared next-key locks on the index records it encounters. Esme tame, kad "sets shared(!) next-key locks", kas leidzia ta pati padaryti kitai serial transakcijai, nes S ir S pora yra compatible (zinoma as darau prielaida, kad konkreciam vapyzdy id yra pirminis raktas) t.y. 2 transakcijos begin transaction select * from tbl where id = 5 delete from tbl where id = 5 end transaction tarpusavyje nekonfliktuoja tol, kol nei viena is ju nepasieke delete sakinio. Konfliktas atsiranti tik tada, kai bent viena transakcija sukurs X locka. Taigi, potencialiai visos transakcijos po pirmos, kurios pataike prasideti tarp pirmosios transakcijos begin transaction ir X locko sukurimo, is esmes yra siuksles, nereikalingai apkraunancios sistemos darba, nes jos ivykdys delete tik tuo atveju, jei ankstesne transakcija buvo abortinta. Prie viso to, takrim pirmoji transakcija jau sukure X locka, bet uzklausimu skaicius nesustoja, sistemai toliau kuriami uzklausimai su naujomis tokiomis paciomis transakcijomis. Sios naujosios transakcijos, negali sukurti ir S locko, tam, kad ivykdyti selecta, nes pirmoji yra sukurusi X locka tam paciam irasui (vel ziuriu lock type compatibility matrix, matau X ir S pora yra conflicting). Kaip MySQL elgsis tokiu atveju as nzn, reikia ziureti, bet variantai, kuriuos dabar galiu sugalvoti yra tokie: 1. Restartuoti naujausias transakcijas rysium su tuo, kad irasas, kuriam jos negalejo sukurti S locku, nebeegzistuoja (restartuoti=rollback+pradeti nuo pradziu). 2. Grazinti exceptiona row does not exist ar pan. 3. Abortinti transakcija. Noreciau atkreipti demesi, kad bet kuris is situ variantu reikalaus papildomu veiksmu is DBVS, kuri savo algoritmais tures atpazinti tokias situacijas t.y. dar papildomai apkraus sistema. Taigi, visos transakcijos, kurios yra sukurtos tuo metu kai yra vykdoma pirmoji transakcija yra tik papildoma apkrovima sistemai, kuri realiai neduoda jokio rezultato, nes neatlieka jokiu veiksmu. Tiketis greitaveikos pagerejimo galima tik is MySQL vidiniu resursu, t.y. darant prielaida, kad InnoDB susitvarkys greiciau su transakcijomis (iskaitanta tas, kurios sukasi be jokio rezultato), palyginus su ISAM write lock komanda. Man tai labiau panasu yra lavono reanimavima, negu sprendima t.y. takrim ISAM pradeda stabdyti nuo 30 konkurentiniu vartotoju, na gerai InnoDB prades stabdyti nuo 100. Esme tame, kad pasiekus ta 100 visvien bus sakes. Tada lieka tik pasiulymas - nusipirkit greitesni proca. Man asmeniskai butu zema siulyti nusipirkti greitesni proca, nepasiulius kitu alternatyvu :) Neturiu po ranka MySQL, galbut cia kasnors galetu pagelbeti ir atlikti tai, ka as pabandziau su Oracle. Tai labai paprasta ir uzima gerokai maziau laiko negu man parasyti sita posta :) Stai pavyzdiai is Oracle create table TST ( ID NUMBER not null, NOTE VARCHAR2(2000), constraint TST_PK primary key (ID) ) insert into TST (ID, NOTE) values (1, null); insert into TST (ID, NOTE) values (2, null); insert into TST (ID, NOTE) values (3, null); insert into TST (ID, NOTE) values (4, null); insert into TST (ID, NOTE) values (5, null); commit; susikuriau 3 sesijas (3 tam, kad patikrinti ar nebus deadlocku) su vienodom transakcijom ir paleidau jas vienu metu READ COMMITED atveju session 1 SQL> set serveroutput on; SQL> declare 2 i number; 3 begin 4 set transaction isolation level read committed; 5 select id into i from tst where id = (select min(id) from tst) ; 6 dbms_output.put_line('id=' || i); 7 delete tst where id = i; 8 dbms_lock.sleep(10); 9 dbms_output.put_line(sql%rowcount || ' row(s) deleted'); 10 commit; 11 end; 12 / id=1 1 row(s) deleted PL/SQL procedure successfully completed. session 2 SQL> set serveroutput on; SQL> declare ..... tas pats kas auksciau id=1 0 row(s) deleted session 3 SQL> set serveroutput on; SQL> declare ..... tas pats kas auksciau id=1 0 row(s) deleted t.y. READ COMMITED atveju oracle tiesiog abortina 2 ir 3 transakcijas SERIALIZABLE atvejis session 1 SQL> ed Wrote file afiedt.buf 1 declare 2 i number; 3 begin 4 set transaction isolation level serializable; 5 select id into i from tst where id = (select min(id) from tst) ; 6 dbms_output.put_line('id=' || i); 7 delete tst where id = i; 8 dbms_lock.sleep(10); 9 dbms_output.put_line(sql%rowcount || ' row(s) deleted'); 10 commit; 11* end; SQL> / id=2 1 row(s) deleted session 2 SQL> declare ... tas pats kas auksciau id=2 declare * ERROR at line 1: ORA-08177: can't serialize access for this transaction ORA-06512: at line 7 session 3 SQL> declare ... tas pats kas auksciau id=2 declare * ERROR at line 1: ORA-08177: can't serialize access for this transaction ORA-06512: at line 7 jokiu deadlocku, serialines transakcijos tiesiog taip neveikia (bent jau Oracle atveju). Jei MySQL grazins taip pat exception, bus katastrofa, nes, speju, exceptionais pasibaigusiu transakciju bus daugiau negu normaliai pasibaigusiu... Tam, kad pasiketi FIFO principa, reikia ne isolation level keisti, o selectui deti FOR UPDATE (ka turi ir MySQL), tam, kad sis selectas sukurtu X locka, vietoj S locko FOR UPDATE atvejis session 1 SQL> ed Wrote file afiedt.buf 1 declare 2 i number; 3 begin 4 select id into i from tst where id = (select min(id) from tst) FOR UPDATE; 5 dbms_output.put_line('id=' || i); 6 delete tst where id = i; 7 dbms_lock.sleep(10); 8 dbms_output.put_line(sql%rowcount || ' row(s) deleted'); 9 commit; 10* end; 11 / id=3 1 row(s) deleted PL/SQL procedure successfully completed. session 2 SQL> declare .... tas pats kas auksciau id=4 1 row(s) deleted PL/SQL procedure successfully completed. session 3 SQL> declare .... tas pats kas auksciau id=5 1 row(s) deleted PL/SQL procedure successfully completed. Va dabar viskas buvo ivykdyta is eiles, kadangi kiekviena sekanti transakcija prasidejo tik po to, kai baigesi ankstesnioji. Visos 3 ivyko leciau nei pirmi 2 atvejai, nes buvo vykdomos grieztai is eiles. Tiesiog siuo konkreciu atveju su tokiu select for update, nera jokio skirtumo ar rakinti viena irasa ar visa lenta, greitaveika bus ta pati...