» »

Mariadb (InnoDB) istočasni insert v tabelo iz različnih procesov

Mariadb (InnoDB) istočasni insert v tabelo iz različnih procesov

«
1
2

HotBurek ::

Dobro jutro.


Zanima me, kako rešujete problem vzporednega, istočasnega insertanja podatkov iz različnih procesov v isto tabelo (MariaDB, InnoDB)?

Npr. da imam en process, ki dela v while loop-u in dela sledeče:
# start transaction
START TRANSACTION READ WRITE;

# get current max id
SELECT MAX(`id`)
FROM `database`.`table`
INTO @maxid;

SET @maxid = @maxid + 1;

# now make insert
INSERT INTO `database`.`table` (`id`) VALUES (@maxid);

# commit transaction
COMMIT;

Če sedaj poženem vzporedno drug proces, ki prav tako vnaša podatke v isto tabelo, občasno dobim error "duplicate id".

Kakšne so bolj ali manj elegante rešitve za ta problem?

Ena rešitev je preko vmesnih temp tabel: https://softwareengineering.stackexchan...
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window
  • spremenilo: HotBurek ()

MH0 ::

Zakaj pa ne auto increment?

OracleDev ::

Točno to, al pa če ma mariadb sekvence. Tisto z max so delal 20 let nazaj pa še takrat bi jih odpustu.

HotBurek ::

Autoincrement mi ni všeč čisto iz estetskega razloga.

In ta je, da začne štet pri 1 in ne 0. 8-O

To bi sicer lahko pofixal, in vnesel prva dva row-a na roke, potem pa auto...
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

MH0 ::

Meni pa se zdi dobro, če ostane ničla neuporabljen ID. :-)

mr_chai ::

dfaq ? Zakaj ti ni všeč, da začne štet od 1. Pa si mogoče pomislil, da obstajajo kje kakšna nastavitev, da ti začne šteti iz 0 ?

V tvojem primeri se dogaja sledeče. Recimo, da imaš v bazi samo eno vrstico z ID-jem 1.

Process1...getMaxId , vrne 1
Process2...getMaxID , vrne 1
Process1...Insert [id 2]
Process1...Commit
Process 2...Insert [id 2]
Process 2...Commit
BANG!

Utk ::

HotBurek je izjavil:

Autoincrement mi ni všeč čisto iz estetskega razloga.

In ta je, da začne štet pri 1 in ne 0. 8-O

WTF? Za id ti je po definiciji vseeno kak je. Tudi če bi bil to nek guid.

Zgodovina sprememb…

  • spremenil: Utk ()

OracleDev ::

Sej pravm, odpuščen :)

shm ::

Če res hočeš naredit na ta način lahko zamenjaš start transaction... z LOCK TABLE `database`.`table` WRITE WAIT in commit z UNLOCK TABLES.

Ampak veliko boljši način je autoincrement, kot so ti že predlagal. UUID namesto številke bi blo pa še boljš.

HotBurek ::

Z 0 začet ne gre.

AUTO_INCREMENT columns start from 1 by default. The automatically generated value can never be lower than 0.

Vir: https://mariadb.com/kb/en/auto_incremen...


To, da ti je za id vseeno, kakšno vrednost ima... Well, različni smo. Mene motijo že gap-i (0, 1, 2, 4), če brišem nekje na sredini.


Kar se tiče hendlanja v primeru, da pride do konflikta (kot je opisal mr_chai), imam rešeno, da se insert izvaja v loop-u (max 6 krat), dokler insert ni uspešen. Vsak loop ima time.sleep dolg nekaj 100 ms.

A kadar proces, ki dela v while loop-u, na polno tolče inserte, drug proces nima šans, da pride zraven. In faila 6x, kar je na koncu insert fail.


Ena opcija, za katero bi šlo, je da se insert ukazi pišejo v log file:
process_01.txt
process_02.txt

Potem pa insert process v single mode-u to pograbi in požene. Slaba stvar je, da je tak sistem asinhronski.


Druga opcija je, da bi razdelil id pool-e in jih dodelil različnim procesom (ti so trenutno trije).

Se pravi:
process_01 id_pool = 0 to 999999
process_02 id_pool = 1000000 to 1999999
process_03 id_pool = 2000000 to 2999999

To bi delalo, malo bi moral pofixat, kako dobit maxid za posamičen pool. A nastali bi ti gap-pi.


Tretja opcija je, da bi proces, ki je poizkusil insert, in je dobil duplicate error za id, v file zapisal neko vrednost (npr. 2022-06-21-21-42-07---2022-06-21-21-42-12) in s tem drugim signaliziral, da naj naredijo v tem časovnem obdobju med insertom time.sleep.


LOCK TABLE ne gre, ker: LOCK is not allowed in stored procedures

Z UUID še nisem delal. Zgleda dobra rešitev. Kako pa v takem primeru sortiraš glede na čas insert-a?
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

Utk ::

OracleDev je izjavil:

Sej pravm, odpuščen :)

Druge ni.

AndrejS ::

Jaz ti priporočam da opustiš programiranje. Za ID se vedno uporabi autoincrement na nivoju baze - ali pa za ID uporabiš GUID. Ker tak ko ti to delaš- bo prišlo do katastrofe, ko boš 1x imel veliko podatkov v kratkem časovnem obdobju za vstavit

Glede sortiranja na čas inserta pa dodaš stolpec created (timestamp) - CURRENT_TIMESTAMP()

Zgodovina sprememb…

  • spremenil: AndrejS ()

Utk ::

Tu ne more prit do večje katastrofe kot je že katastrofa to insertanje.

MH0 ::

AndrejS je izjavil:

Jaz ti priporočam da opustiš programiranje. Za ID se vedno uporabi autoincrement na nivoju baze - ali pa za ID uporabiš GUID. Ker tak ko ti to delaš- bo prišlo do katastrofe, ko boš 1x imel veliko podatkov v kratkem časovnem obdobju za vstavit

Glede sortiranja na čas inserta pa dodaš stolpec created (timestamp) - CURRENT_TIMESTAMP()

In to točno tako, kot ti je napisal, čas iz baze, ne iz klijenta!

HotBurek ::

Well, neke katastrofe ni, ker insert fail-a in ga potem kmalu kasneje, ponovno poizkuša vnest. Rahlo je moteče, ker se takrat piše v error log. In sem pol prestrašen po nepotrebnem.

Čas inserta pa seveda vnesem iz klienta, ker mi je v Python-u lažje (in hitreje) spisat, kot v SQL-u. 8-)
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

mr_chai ::

HotBurek je izjavil:

Z 0 začet ne gre.

AUTO_INCREMENT columns start from 1 by default. The automatically generated value can never be lower than 0.

Vir: https://mariadb.com/kb/en/auto_incremen...


To, da ti je za id vseeno, kakšno vrednost ima... Well, različni smo. Mene motijo že gap-i (0, 1, 2, 4), če brišem nekje na sredini.


Kar se tiče hendlanja v primeru, da pride do konflikta (kot je opisal mr_chai), imam rešeno, da se insert izvaja v loop-u (max 6 krat), dokler insert ni uspešen. Vsak loop ima time.sleep dolg nekaj 100 ms.

A kadar proces, ki dela v while loop-u, na polno tolče inserte, drug proces nima šans, da pride zraven. In faila 6x, kar je na koncu insert fail.


Ena opcija, za katero bi šlo, je da se insert ukazi pišejo v log file:
process_01.txt
process_02.txt

Potem pa insert process v single mode-u to pograbi in požene. Slaba stvar je, da je tak sistem asinhronski.


Druga opcija je, da bi razdelil id pool-e in jih dodelil različnim procesom (ti so trenutno trije).

Se pravi:
process_01 id_pool = 0 to 999999
process_02 id_pool = 1000000 to 1999999
process_03 id_pool = 2000000 to 2999999

To bi delalo, malo bi moral pofixat, kako dobit maxid za posamičen pool. A nastali bi ti gap-pi.


Tretja opcija je, da bi proces, ki je poizkusil insert, in je dobil duplicate error za id, v file zapisal neko vrednost (npr. 2022-06-21-21-42-07---2022-06-21-21-42-12) in s tem drugim signaliziral, da naj naredijo v tem časovnem obdobju med insertom time.sleep.


LOCK TABLE ne gre, ker: LOCK is not allowed in stored procedures

Z UUID še nisem delal. Zgleda dobra rešitev. Kako pa v takem primeru sortiraš glede na čas insert-a?



8-O 8-O

Kot so že zgoraj omenili, mislim da je edina rešitev prekinitev delovnega razmerja.
No resnično upam, da ne bodo te tvoje "rešitve" laufale kje na produkciji in probavaš bedarije kar tako za hec.

OracleDev ::

HotBurek je izjavil:

Well, neke katastrofe ni, ker insert fail-a in ga potem kmalu kasneje, ponovno poizkuša vnest. Rahlo je moteče, ker se takrat piše v error log. In sem pol prestrašen po nepotrebnem.

Čas inserta pa seveda vnesem iz klienta, ker mi je v Python-u lažje (in hitreje) spisat, kot v SQL-u. 8-)


Sori ampak a se ti zavedaš kakšne pišeš... Predlagam ti da zbrišeš vse in tut to temo

Lonsarg ::

Če bi prvi post bil zgolj akademsko vprašanje bi ti odgovoril da je rešitev uporaba "Serializable" isolation level (default je "read commited"), ki bo poskrbel da je tudi read zablokiran med transakcijami in bo torej izvedel striktno eno za drugo in ne bo nikoli konflikta. Za več branja tu: https://mariadb.com/kb/en/mariadb-trans... Velja upozorilo, da serializable isolation level čisto iz performančnega vidika načeloma nočeš nikoli uporabit, razen ko res res ne gre drugače. Pa še takrat je morda softwerski locking boljša rešitev kot serializable transakcija.

Ampak ponavljam to ima zgolj akademsko vrednost, ali pa recimo kak edge use case kjer ne smeš sheme spreminjat na bazi. Da pa nekdo noče identity ali sekvence uporabit in gre raje take hacke delat samo ker se mu tako zahoče pa je norost.

Zgodovina sprememb…

  • spremenil: Lonsarg ()

WhiteAngel ::

HotBurek je izjavil:


Kar se tiče hendlanja v primeru, da pride do konflikta (kot je opisal mr_chai), imam rešeno, da se insert izvaja v loop-u (max 6 krat), dokler insert ni uspešen. Vsak loop ima time.sleep dolg nekaj 100 ms.


8-O

GupeM ::

HotBurek je izjavil:

Čas inserta pa seveda vnesem iz klienta, ker mi je v Python-u lažje (in hitreje) spisat, kot v SQL-u. 8-)

Si kdaj pomislil na to, kaj se bo zgodilo, ko bosta dva klienta z nekoliko različnim časom pisala v bazo? Točno tako. Sortiranje po času ne bo več delovalo pravilno. Kaj se bo zgodilo, ko bo nekdo z drugega časovnega pasu pisal v bazo?

Pri simulatorjih se pogosto uporablja tudi virtualni čas. Bi v tem primeru v bazo pisal virtualni čas pod čas nastanka/modifikacije?

Pri insertu vedno uporabljaj čas baze, ne klienta. No, lahko zraven daš še čas klienta, čist tko za info, če že hočeš.

Za ID pa autoincrement oz sekvence.

Za te stvari mora skrbeti baza, ne client. Če bi te stvari prepustil bazi, ne bi rabil tele teme, projekt bi bil pa že zaključen. Tako pa ugotavljaš, kako izvajati simple inserte z več procesov.

driver_x ::

Če bi take stvari delal kdo od mojih zaposlenih, bi sledila razlaga v stilu nekaj odgovorov v tej temi. Če bi še vedno vztrajal pri taki rešitvi, bi bil premeščen na kakšno delovno mesto, kjer ni predvideno delo z računalnikom.

HotBurek ::

GupeM, za slabost (oz. več njih) vnosa datuma iz klienta za "čas vnosa" v bazo vem. Vseeno hvala za deljenje informacij in obrazložitev.

Moram pa rečt, da sem kar malo presenečen, koliko se vas je odzvalo z željo po pumpanju lastnega ego-ta. Nisem vedel, da je tako hudo.

Pa lep dan še naprej. :)
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

kuall ::

mssql:
Preprečimo, da bi 2 vrstici dobili isti ID:
create table _test55 (id int)
BEGIN TRANSACTION
DECLARE @id INT = ISNULL (((SELECT MAX(id) FROM _test55 WITH (TABLOCKX))), 0) + 1
INSERT INTO _test55 (id) VALUES (@id)
COMMIT


drgač pa se ne strinjam z loleki, ki se zgražajo. skor nikoli se ne strinjam z loleki,. ki se zgražajo. človek se uči, zato pa postavlja vprašanja, ne mu zdej predlagat, da naj neha s programiranjem, če postavi "neumno" vprašanje. pumpanje lastnega ega itak ,ker očitno vam nekaj manjka pas rabite samopotrditev v virtualnem svetu. :)

Zgodovina sprememb…

  • spremenilo: kuall ()

mr_chai ::

Sploh se ne gre za ego in pumpanje. Problem HotBureka(kualla?), je ravno v tem, da ko dobi dober nasvet, še vedno vztraja kako je njegova rešitev dobra in da sploh ni slaba. To lahko vidiš pri vseh njegovih IT-jevskih vprašanjih. Če se imaš namen učiti, ni problema, samo prosim, če ne upoštevaš dobrih nasvetov, kaj je potem sploh point spraševanja tule po slo-techu ? MIslim, da je bolj problem njegovega ega, kot našega. Če se hočeš česa naučiti, si moraš včasih priznati, da mogoče pa nekaj nisi dobro naredil. In to velja za vse, junior, seniorje in super savante.

Utk ::

Nihče mu ni rekel, da naj pusti programiranja zarad vprašanja. Smo mu pa rekli zato, ker je tudi po odgovorih, da se tako ne dela, vztrajal pri svoji bedasti "rešitvi". Tu pa ni več izgovorov. Nekaj je če ne znaš, nekaj drugega pa če vztrajaš pri idiotizmu in si ne daš dopovedat kako narobe je to. Takemu se nikoli ne bo dalo nič dopovedat, in z večjimi projekti bojo bedarije samo naraščale. Naj neha dokler je še čas. Tu ni pumpanja ega, ker tu res ni nič takega na čemur bi kdo lahko pumpal ego. To je osnovno zapisovanje v bazo, madona. Vsak s 6 urnim tečajem sqla nima več problema s tem.

kuall ::

Utk je izjavil:

Nihče mu ni rekel, da naj pusti programiranja zarad vprašanja.


AndrejS je izjavil:

Jaz ti priporočam da opustiš programiranje.

Slabo berete.

Zgodovina sprememb…

  • spremenilo: kuall ()

mr_chai ::

Kuall, tudi ta tvoja rešitev je slaba.

Utk ::

kuall je izjavil:

Utk je izjavil:

Nihče mu ni rekel, da naj pusti programiranja zarad vprašanja.


AndrejS je izjavil:

Jaz ti priporočam da opustiš programiranje.

Slabo berete.

Očitno si ti tist, ki slabo bere. To smo mu predlagali šele potem ko je "razložil" zakaj ne mara autoincrement.

Zgodovina sprememb…

  • spremenil: Utk ()

kuall ::

mr_chai je izjavil:

Sploh se ne gre za ego in pumpanje. Problem HotBureka(kualla?), je ravno v tem, da ko dobi dober nasvet, še vedno vztraja kako je njegova rešitev dobra in da sploh ni slaba.

če sem jaz dobil kak dober nasvet na slo techu sem ga vsekakor upošteval, ampak so žal zelo redki. večinoma je samo lajanje. debata o null je bila bolj akademska, ali pa enkrat debata o decimal: nisem se naučil nič novega tam kar ne bi že vedel, za decimal/float sem moral potem sam poguglat, da sem dobil pravo razlago, ker mi razni jypeti niso bili sposobni razložiti, razen to sem se naučil, da slo tech raja rada nesramno laja in si pumpa ego.

mr_chai je izjavil:

Kuall, tudi ta tvoja rešitev je slaba.

imaš boljšo? nalimaj, ne da samo lajaš, bom tisto uporabljal, če je res boljše. razen identity/autoincrement, kar je očitno seveda boljša rešitev, ampak včasih rabiš tudi to.

Zgodovina sprememb…

  • spremenilo: kuall ()

HotBurek ::

Jaz nikjer ne vstrajam, da tako kot sem trenutno postavil insert, da se tako dela in da je to najboljš rešitev.

Dobil sem odgovor, da naj namesti INT za id uporabim UUID. Kar bom, mogoče ob enem izmed naslednjih rewrite-ov, tudi naredil. Mogoče. Ampak ta informacija je koristna, tudi za druge, ki se bodo znašel v isti situaciji.

Kar se pa ostalega tiče, je bilo pa veliko nepotrebne ego-eko-solate.

Tako da hvala za koristne informacije. Now, lets move on.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

Zgodovina sprememb…

  • spremenilo: HotBurek ()

kuall ::

te nič ne zanima zakaj naj bi bil UUID boljši kot INT ali boš kar ne slepo verjel enemu slo tech mešetarju?

še odgovor na čist prvo vprašanje v temi, na katerega seveda noben ni dal odgovra, ker ne ve:

v selectu rabiš TABLOCKX, ne vem kaj je ekvivalenta v mysql, ker tudi če začneš transkacijo in narediš select ti to ne bo zaklenilo tabele, TABLOCKX jo zaklene. tako lahko 2 selecta v istem času zgenerirata isti ID in imaš tvojo napako.

najboljša lastnost dobrega programerja je, da poskuša razumet vse, kar dela.

Zgodovina sprememb…

  • spremenilo: kuall ()

mr_chai ::

kuall je izjavil:

mr_chai je izjavil:

Sploh se ne gre za ego in pumpanje. Problem HotBureka(kualla?), je ravno v tem, da ko dobi dober nasvet, še vedno vztraja kako je njegova rešitev dobra in da sploh ni slaba.

če sem jaz dobil kak dober nasvet na slo techu sem ga vsekakor upošteval, ampak so žal zelo redki. večinoma je samo lajanje. debata o null je bila bolj akademska, ali pa enkrat debata o decimal: nisem se naučil nič novega tam kar ne bi že vedel, za decimal/float sem moral potem sam poguglat, da sem dobil pravo razlago, ker mi razni jypeti niso bili sposobni razložiti, razen to sem se naučil, da slo tech raja rada nesramno laja in si pumpa ego.

mr_chai je izjavil:

Kuall, tudi ta tvoja rešitev je slaba.

imaš boljšo? nalimaj, ne da samo lajaš, bom tisto uporabljal, če je res boljše. razen identity/autoincrement, kar je očitno seveda boljša rešitev, ampak včasih rabiš tudi to.



Saj smo ti zgoraj omenili. Na evo ti nalimam to kar bi moral HotBurek narediti pri svoji tabeli. Primer iz Postgresa.

      CREATE TABLE kurceva_tabela( 
      id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, 
      neki TEXT,
      created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW());



It to je vse kar on rabi, če bi ga dejansko pozorno prebral, bi videl, da bi on rad samo sortiral podatke po datumu kreiranja vrstic v tabeli. In on se je problema lotil na napačen način, hotel je namreč dobiti vrstni red vstavitve podatkov z generiranjem lastnega id-ja. Da greš pa sam poizkušat implementirat nekaj kar ima baza že interno implementirano, je pa res malo mimo no.

In povej mi dragi kuall, kdaj bi ti rabil to rešitev tvojo oziroma od HotBureka ? Ti si tisti ki tukaj nekaj brez veze laja. Ravno point našega zgražanja je v tem, da te vajine "rešitve" za vnos podatkov v tabelo ne rabiš NIKOLI!

kuall ::

nikoli je močna beseda.

primer1: firma ima identity številko x in y pozicij zaposlenih. unikatni index na (x,y). y moraš ročno povečati. za y uporabiš mojo kodo. seveda se da drugače organizirati stvari v tem primeru ampak če bi rad, da ima vsak v firmi svojo unikatno zaporedno številko, ki jo ponavadi potem tudi prikazuješ uporabnikom v programu, uporabiš ta način.

to rešitev vstavljanja idja ročno sem videl že velikokrat, pa ne v svoji kodi. jaz vedno uporabim identity primary key pa je mir, pa DateTimeIns default getdate ().

sicer pa sem ziher, da identity kolona uporablja isti lock mehanizem zadaj kot moja koda, drugo itak ni možno:
https://mohewedy.medium.com/mssql-ident...

jaz razumem ta forum kot bolj filozofsko razpravljanje, vi pa kot neko obrt.

Utk ::

Sem precej ziher, da dolgi lock v tem primeru povzroči transakcija, ne pa sam insert. Insert ne rabi iskat največjega idja, ker ima stalno pripravljenega naslednjega. Če izbrišeš zadnjo vrstico, ne bo njenega idja dobil naslednji insert, kar je tudi prednost autoincrementa pred nekim skropucalom.
Da nekdo rabi članek, ki mu pove, da ni dobra ideja klicat nek webservis dokler imaš odprto transkacijo, je tudi žalostno.

primer1: firma ima identity številko x in y pozicij zaposlenih. unikatni index na (x,y). y moraš ročno povečati. za y uporabiš mojo kodo. seveda se da drugače organizirati stvari v tem primeru ampak če bi rad, da ima vsak v firmi svojo unikatno zaporedno številko, ki jo ponavadi potem tudi prikazuješ uporabnikom v programu, uporabiš ta način.

Ne. Uporabiš tabelo za firme in tabelo za pozicije, povežeš s FK, pa bo vse avtomatsko štimalo.

Zgodovina sprememb…

  • spremenil: Utk ()

kuall ::

Transakcija ne naredi locka vedno.
naredi
begin tran select * end tran
tu ne bo nobenega locka
tudi insert brez identity kolone ne naredi locka.

Nima web servis veze, nisi razumel. to je bistvo članka:
The same effect can be tested aside from any backend service by opening two SQL Terminals and in the first terminal issue the following:


begin tran
    insert into audit (msg) values ('some message');
    WAITFOR DELAY '00:01';  -- wait for 1 minute
commit;

and in the second terminal execute the following:

select * from audit

you will notice the select statement will be blocked until the first transaction ends, meaning that the insert statement with the identity brings a table-level lock.


če insert z identity zaklene celo tabelo to pomeni, da uporablja isti mehanizem kot moja koda.


Ne moreš narediti fk na kolone, kjer se številke podvajajo, kot bi bilo to primer v zaposlenih. ne razumem ,kako bi ti to rešil z 2 tabelama. koda?

Zgodovina sprememb…

  • spremenilo: kuall ()

c3p0 ::

Vsi nasveti do zdaj so zanič.

Pravilna rešitev je pohekat M/a/y/ria/SQL source kodo, da bo auto_increment deloval tako kot je tebi vizualno všeč.

Nato v vsak projekt, ki ga delaš dodaš kot req. še lasten server s custom *SQL instalacijo in še več zaslužiš.

Utk ::

Če imaš samo select v transakciji, zakaj bi potem lockalo?
Če poženeš 1000 insertov naenkrat, se jih bo vseh 1000 prav izvedlo. V transakciji ali brez.
Ne, insert ne dela tako kot si ti napisal, zato ker če zadnji zapis izbrišeš, novi ne bo dobil njegovega idja. Tabela ima zmeraj pripravljen naslednji id in ko ga en insert vzame, se poveča.
Tvoj način mora zaklenit tabelo, drugače ne bi delal niti približno. Insert zaklene tabelo v transakciji pa zato, ker dokler ni commita, baza pač ne ve kater bo naslednji id, ali bo trenutni insert commitan, itd. To je čisto nekaj drugega. Insert lahko zaženem brez transakcije, 1000 njih naenkrat, in vsi se bojo prav izvedli.

Ne moreš narediti fk na kolone, kjer se številke podvajajo, kot bi bilo to primer v zaposlenih. ne razumem ,kako bi ti to rešil z 2 tabelama. koda?

Če je ista pozicija v različnih firmah pač ista, imaš lahko skupne pozicije. Če ima vsaka firma čisto svoje, zakaj se bi sekiral ali se podvajajo ali ne?

Utk ::

Da ne govorimo o tem kako bi te vaše "solucije" delale ko bi imel 5 insertov naenkrat. Pustimo 1000...

kuall ::

moja solucija je uporaba iodentity kolone, da si ne boš kaj naredil. vidim, da si še vedno nisi napumpal ega. :D samo razpravljamo teoretično, da se kaj naučimo...

tudi če narediš insert z identity kolono brez transakcije bo ta insert tabelo moral zakleniti v ozadju. edina razlika je, da ima identity način shranjen nekje max id v neki globalni tabeli, da je pač id vedno unikaten, tudi če brišeš, kar je dobro, se strinjam, bolje, kot da se podvajajo. no če pa hočeš, da ni praznih mest, če brišeš potem moraš uporabit burekov orig način brez identity kolone. kdaj bi znalo tudi to prav priti. čeprav baje obstaja nek reseed. mogoče bi kdaj hotel imeti določen razmik itd.

>Če imaš samo select v transakciji, zakaj bi potem lockalo?

vpraš bureka, zakaj je sklepal, da mu select v transakciji locka. na tej napačni domnevi je potem debelo gledal, zakaj mu ne dela.


ja lahko narediš novo tabelo
tabla_pozicije (int id identity, int pozicija)
je pa malenkost nerodno, ampak pravi način i guess.

Zgodovina sprememb…

  • spremenilo: kuall ()

no comment ::

kuall je izjavil:


če insert z identity zaklene celo tabelo to pomeni, da uporablja isti mehanizem kot moja koda.

Nima veze identity ali ne. Vsaj probaj preden razlagaš napačne stvari naprej...

Se pa ne strinjam s tistimi, ki bi odpuščali HotBureke, ker da NIKOLI ne rabiš telovadit z unikatnostjo in da ti vse probleme reši identity. Včasih moraš shranit tudi kakšno "lepše" unikatno zaporedje ali (pol)govorečo šifro in takrat imaš podoben problem.

win64 ::

kuall je izjavil:

mssql:
Preprečimo, da bi 2 vrstici dobili isti ID:

create table _test55 (id int)
BEGIN TRANSACTION
DECLARE @id INT = ISNULL (((SELECT MAX(id) FROM _test55 WITH (TABLOCKX))), 0) + 1
INSERT INTO _test55 (id) VALUES (@id)
COMMIT


drgač pa se ne strinjam z loleki, ki se zgražajo. skor nikoli se ne strinjam z loleki,. ki se zgražajo. človek se uči, zato pa postavlja vprašanja, ne mu zdej predlagat, da naj neha s programiranjem, če postavi "neumno" vprašanje. pumpanje lastnega ega itak ,ker očitno vam nekaj manjka pas rabite samopotrditev v virtualnem svetu. :)


Samo opozorilo za druge(ti ga očitno ne potrebuješ) : ta koda ne zagotavlja nobene zaščite. Še zmeram imaš race condition, ko dve transakciji hkrati pridobivata id.

kuall ::

ena transakcija bo dobila deadlock/timeout, to hočeš povedat? al se sploh ne da to rešit drugače kot z identity kolono?

kuall ::

tu bi bilo treba malo naštudirat TRANSACTION ISOLATION LEVEL...

po moje default (vsaj ms sql server) tako dela, da počaka druga transkacija neskočno dolgo, dokler prva ne konča. v tem primeru deadlocka ne bi nikoli dobil?

sprašujem zdej ne spet lajat :))

win64 ::

kuall je izjavil:

ena transakcija bo dobila deadlock/timeout, to hočeš povedat? al se sploh ne da to rešit drugače kot z identity kolono?

To, da začneš s transakcino ne pomeni da bo katerakoli tabela samodejno zaklenjena. In tudi select sam po sebi ne bo ničesar zaklenil.

Situacija je lahko tudi naslednja:
- seja 1 zažene stavek za max id
- seja 2 zažene stavek za max id
- seja 1 poizkuša zapisati
- seja 2 poizkuša zapisati - zapisa ne zaradi napake

Zato bi moral prvo zakleniti celo tabelo. In potem se greš lahko branje.
Ampak ne zaklepat celih tabel zaradi takih stvari. In tudi max načeloma mora prebrati celo tabelo da sploh vrne vrednoat.

kuall ::

to kar si zdaj napisal smo vse že napisali v tej temi. tablocx (mssql) zaklene celo tabelo

If you are in a transaction and you grab an exclusive lock on a table, EG:

SELECT 1 FROM TABLE WITH (TABLOCKX)

No other processes will be able to grab any locks on the table, meaning all queries attempting to talk to the table will be blocked until the transaction commits.


to, da morajo biti transkacije karseda kratke časovno tudi že vemo. nasploh se jih je dobro izogibati, če se da.
tudi sam update je transakcija in delati velike update je enako nevarno kot delati dolge transakcije. bolje update razbiti na več manjših magar v kurzorju. :D taka je praksa.



tak da nič novega me nisi naučil, žal. imaš sploh kaj novega, da se naučim od tebe?

kuall ::

win64 je izjavil:

In tudi max načeloma mora prebrati celo tabelo da sploh vrne vrednoat.

načeloma spljoh ne, saj imajo idji index. celo tabelo se bere, ko se dela table scan (ni indexa), ne seek (je index). index seek po moje najde v prvem ali drugem poskusu z uporabo max(id), tak da vrne takoj.

Lonsarg ::

Tako je tablock je ena opcija da zaklenes tudi branje med transakcijami.

Druga opcija je isolation level serializable ki ti garantira lock tudi za read operacije (v bistvu ta isolation level simulira zaporedno izvajanje transakcij), kar seveda performancno ni lih optimalna resitev.

Zgodovina sprememb…

  • spremenil: Lonsarg ()

HotBurek ::

Dobro jutro.


Evo, fantje in dekline, sedajle sem pognal dva "masovna" inserta: enega po tastarem (maxid + 1), enega z uuid.

In ne boste verjetli, kakšne so prve ugotovitve. Tista rešitev z uuid je malenkost hitrejša. Od oka za x10, x100. I like it. 8-)

Sedaj me pa zanima glede definicije row-a, kamor shranjujete uuid:

- Kater tip uporabljate za ta row?
- Kater index uporabljate za ta tip?

Moj trenutni setup je: varchar(36) tip, ter hash unique index.
root@debian:/# iptraf-ng
fatal: This program requires a screen size of at least 80 columns by 24 lines
Please resize your window

OracleDev ::

a bejž, da je hitrej če ne bereš cele tabele ob vsakem insertu. In če bi uporabljal auto increment spet ne bi imel teh vprašanj. Postav ga na tolk velikosti kolkr pač maš max velikost ta svoj uuid.

Zimonem ::

Dobivam občutek, da SQL baza sploh ni prava rešitev na kateri bi gradil aplikacijo.
«
1
2


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[SQL] primary key inkrementalno dodajanje (strani: 1 2 )

Oddelek: Programiranje
515200 (4390) ejresnevem
»

Učenje programiranja PHP

Oddelek: Programiranje
91445 (986) Spura
»

SQL pomoč

Oddelek: Programiranje
132335 (1749) miko22
»

[Sql] Poizvedba

Oddelek: Programiranje
111781 (1432) ales85
»

[T-SQL] Kako vnest podatek v bazo in da ti hkrati vrne id?

Oddelek: Programiranje
162852 (2570) dmok

Več podobnih tem