Jump to content
php.lv forumi

MySQL un unikālais ieraksta numurs


black

Recommended Posts

Pieņemsim, klients vēlas zināt pasūtījuma (order) kārtas numuru. Tā kā ir vēl citi klienti, tad MySQL auto_increment izmantot nesanāks. Kādi vēl varianti?

 

Pašlaik doma ir aptuveni šāda:

LOCK TABLE orders;
SELECT COUNT(*)+1 FROM orders WHERE client_id=x;
INSERT INTO orders (id, data) VALUES ($id, $something);
UNLOCK TABLE orders;

Link to comment
Share on other sites

Tas, ka viņš nav katram klientam atsevišķi. Piemēram, man orderu tabulā glabāsies divi orderi diviem klientiem:

 

order_id order_nr client_id

1 1 1

2 2 1

3 1 2

4 2 2

 

Klients grib redzēt ordera kārtas numuru SAVIEM orderiem, nevis orderu tabulai vispār. (Es patiesībā neglabāšu orderus, bet labāku piemēru nevarēju izdomāt)

Edited by black
Link to comment
Share on other sites

Vispārīgā gadījumā jebkāds kārtas numurs, kas ir jāievada datubāzē bez caurumiem, ir nenormāli nemērogojams pasākums. Tas ir - visiem citiem lietotājiem nāksies gadīt uz to vienu, kamēr tas pabeigs savu darbu. Ja Tavā sistēmā būs 3 lietotāji, kas dienā ievadīs 5 orderus, tad, protams, par to nav vērts satraukties, bet, ja skaits būs ievērojams, tad šis te var būt ļoooooti šaurs pudeles kakls.

Līdz ar to pirmais scenārijs ir vienmēr no šādas prasības kaut kā tikt vaļā:

- Ja tas ir nepieciešams atskaitēm, tad ģenerē skaitļus pēc kārtas SELECT laikā;

- Ja tas ir nepieciešams tāpēc, ka tā vienmēr ir bijis, tad jaunā sistēma kā reiz ir brīdis, kad saprast, ka DBVS nav papīra kartiņu uzskaites sistēma;

- Ja tas ir tāpēc, ka pasūtītājam liekas ērti, tad izstāsti, ka potenciālās problēmas tas radīs daudz vairāk nekā ieguvumus;

- Ja tas ir tāpēc, ka nepieciešama kaut kāda skaitīšana, tad piedāvā atbilstošu atskaiti;

- Jebkurā citā gadījumā izdomā kādu citu attaisnojumu.

Ir tikai viens gadījums, kad diemžēl neko nevar darīt un tā ir likumdošana.

Tātad šajā gadījumā parastākais scenārijs ir vienā papildus IDu tabulā glabāt maximālo vērtību (šeit acīmredzot tas jādara katram klientam) un tad, kad liek jaunu ierakstu iekšā

1) noloko vajadzīgo ierakstu IDu tabulā, lai neviens cits to nevar updeitot;

2) ieliek jauno ierakstu bāzes tabulā;

3) updeito IDu tabulas ierakstu;

4) commito vai rollbacko transakciju.

 

Nezinu gan vai MySQLā to tā varēs arī tieši izdarīt (visus 4 soļus vienā transakcijā un nolokot 1 ierakstu Idu tabulā). Šai gadījumā vismaz viens lietotājs sabremzēs darbu tikai viena klienta robežās un tai pašā laikā nodrošinās to nepieciešamo prasību.

 

Starp citu - kas notiks, tad, ja tos ORDERu ierakstus pēc tam dzēsīs? Ja kaut vienu no tiem dzēsīs, tad notiks ierakstu pārnumurēšana? Ja nepārnumurēs, tad ar ko caurums vienas vērtības robežās ir labāks par caurumu no vairākām vērtībām?

 

Šai sakarā man ir arīdzan rakstiņš (gan angliski un par Oracli) The curse of gapless sequences. Jebkurā gadījumā neatkarīgi no tā kādu DBVS izmanto - tas fakts, ka šī prasība prasa serializēšanos vienā punktā, paliek spēkā vienmēr.

 

Gints Plivna

http://datubazes.wordpress.com

Link to comment
Share on other sites

Actually MySQL _šāda_ fīča patiesībā ir un bez papildu lockošanas.. diemžēl tikai MyISAM tabulām..

 

Uztaisi tabulu uzliec primary keyu uz (client_id+order_id) tieši šādā kārtībā un autoincrementu uz order_id .. attiecīgi katram client_id būs savs autoincrments..

Tas ir aprakstīts arī http://dev.mysql.com/doc/refman/5.1/en/exa...-increment.html .. tur arī citas šīs fīčas iespējas un mīnusi.

 

 

Vispār jau krietni vienkāršāk/drošāk ir referencēties uz unikāliem ID .. jo pretēji tev vienmēr jāzin divi parametri gan klienta id gan ordera id..

 

Bet tas nu tā.. man jau liekas ka viss ko vajag ir pie outputa ar php sataisīt tos 1,2,3 orderus (ja jau klientam tā gribās), bet slinkums diskutēt - fīča eksistē ;)

Link to comment
Share on other sites

ID| order_id | unix_timestamp | ....

un karto peec timestampa ... saubos vai useris pamaniis ka nav ierakstiit 1,2,3 bet 123456 123457 ....

pie izvades vienkarshi sanumuree...

tas nederees?

edit: vael var izveidot atseviskju tabulu :

ID| user_id | count

 

un pie katra jauna ordera pievienosanas tabulu apdeitot ..

tb :

SELECT cont ..... WHERE user_id .....

Insert --> orederis count+1 ...

Update count tabulu .... count++

---

Principa doma kaa ar sekvencem.....

Edited by Grey_Wolf
Link to comment
Share on other sites

Kavacky, pārnumurēt nemāku (piemēram, orderu tabula tiek sakārtota pēc kaut kāda preču daudzuma, nevis pēc datuma - kā izdomāt, kuram orderim jāraksta kurš nr pēc kārtas?)

 

Grey_Wolf, kārtošana pēc timestamp derētu, ja man nebūtu jākārto arī pēc citām kolonām (orderu kārtas skaitlim jāsaglabājas arī šādā gadījumā)

Par otro variantu - ja neizmanto locking, ir reālas izredzes, ka tiek ievietoti orderi ar vienādiem numuriem.

Link to comment
Share on other sites

Par otro variantu - ja neizmanto locking, ir reālas izredzes, ka tiek ievietoti orderi ar vienādiem numuriem.

ja pareizi visu uztaisa tad sadas iespeja praktiski izslegta --> ja nu vieniigi konkretais klients sledzas klaat no n serveriem vienlaicigi...

un tad arii timestams nepaliidzees....

 

tb --> ja tas taa ir tad bez tranzakcijam & lock table neiztikt , jebkura gadijumaa...

 

---

Ja ir tik liela noslodze --> Meklee peec Oracle ...

Link to comment
Share on other sites

Ja ir tik liela noslodze --> Meklee peec Oracle ...

 

Kāds sakars šeit ir ar Oracle? Jebšu DBVS kā tādu vispār?

Problēmas vai "caveati" uz visām DBVS ir pilnīgi identiskas - LOCKs arī Āfrikā ir locks... Un nebūs starpības vai tu LOCK table uztaisīsi uz MySQL / PGSQL / vai Oracles - funkcionāli un rezultāts ir viens un tas pats.. un oracle noēdis tavu mazo serveri vēl ātrāk..

 

Ir vienkārši no teorijas jāsaprot kas ir "blocking" un kas atomiskas / acid darbības - šeit noslodze pēc būtības nav nekāda - viens process nolocko pārējie gaida rindā.. :)

 

Savukārt transakcijas neviens nav liedzis izpildīt vairākas uzreiz :)

Link to comment
Share on other sites

×
×
  • Create New...