Roze Posted October 9, 2006 Report Share Posted October 9, 2006 Sveiki, varbūt kāds ir saskāries (ganjau ir) un ir kāds know-how par sekojošu lietu: Ir DB (MySQL) tabula ar IDentifikatoru (piem primary key autoinc) - kā jēdzīgāk būtu panākt pēc iespējas mazāku ID lietojumu? Proti lietotājam jāoperē ar ieraksta ID taču ja ierakstu daudz tad standarta autoincrement vērtībā paliek par sešciparu-septiņciparu skaitli un ir neerti. Teiksim ir ieraksti 1 | Babah 2 | Zazah ... 10000 | Tadah Viena doma bija ka tajā brīdi kad lietotājs beidz darbības piemēram ar '2' objektu id tiek pacelts par kaut kādu lielu skaitli teiksim 2 + 10000000, taču tas neko būtisku nedod jo MySQLs pats neprot rejuzot pa vidu esošās tukšās vērtības bet gan tikai no beigām (MAX(id)+1).. Bija doma izmantot papildus tabulu kurā būtu čupa ar mazajiem ID (teiksim 1 - 10000) kuriem temporāri tiek piesaistīti lielās tabulas identifikatori - tas ir no mazās tabulas tiek atselectēts MIN(id) WHERE lielais_id = '', tad iesetojam konkrētjam ID saikni ar lielo id un līdz ko lietotājs darbības beidz atbrīvojam.. Taču rodas problēma ar konkurenci proti līdzko uz mazo tabulu tiek pieprasīta čupa ar MIN(id) loģiski ka sanāk ka daļai no lielās tabulas ID tiek piesaistīts viens mazās tabulas ID, kas nav pareizi. Lockojot tabulas pie SELECTa sanāk ziepes ar parāk daudz pieprasījumiem rindā.. So varbūt ir kāds hints? Link to comment Share on other sites More sharing options...
bubu Posted October 9, 2006 Report Share Posted October 9, 2006 Proti lietotājam jāoperē ar ieraksta ID taču ja ierakstu daudz tad standarta autoincrement vērtībā paliek par sešciparu-septiņciparu skaitli un ir neerti. Kas tieši ir neērti? Link to comment Share on other sites More sharing options...
v3rb0 Posted October 9, 2006 Report Share Posted October 9, 2006 ja useri raksta tos id ar roku un problēma ir ka tas skaitlis ir garš(..tā sapratu, sorry ja pārpratu :) ), tad varbūt, lai viņi raksta id nevis decimālajā skaitīšanas sistēmā, bet kaut kādā citā, piem ar bāzi 36. gan jau ka pārēķināt skaitli no vienas skaitīšanas sistēmas uz citu nebūs īpaši smagi serverim. Link to comment Share on other sites More sharing options...
Roze Posted October 9, 2006 Author Report Share Posted October 9, 2006 bubu neerti ir rakstīt N-ciparu skaitli.. v3rbo aha mēģinājām ar base32 īsāk sanāk bet ir burtni atkal ķeska ;) Link to comment Share on other sites More sharing options...
Delfins Posted October 9, 2006 Report Share Posted October 9, 2006 (edited) Ja godīgi nesapratu jautājumu. Lietotājs operē ar ID?! wtb. Sapratu. A kāpēc burti neērti? Imho, HEX-ā ir OK. (7 simb -> 5 simb) Ja pareizi sapratu domu, tad mana ideja šāda. ...tāpat kā tavējā, tikai atšķirība ir tāda, ka tu kopē `izlietoto ierakstu/ID` uz citu tabulu - steka princips. {LIELA_TABULA} = {MAZA_TABULA} (Postgre vismaz var uztaisīt inheritance) Pie updeita (lietotājs "izmanto" numuru) Kopējam no MAZĀ uz LIELĀ (lielā jau būs savs cits lielais ID, atsauce uz originālo ID arī var palikt, bet tā nebūs unikāla) Nomainam kolonnas FREE vērtību uz 1 iekš MAZĀ Veidojam query `select min(ID) where FREE = 1` no MAZĀS IF (no_row) insert new_ID else ID=NULL (t.b. auto) (iekš MAZĀS) Cerams, ka saprati PS: tikai jāuzmanās ar to min(ID)... Liekas, ka būs jālocko tabula pirms selekta un atlokot pēc updeita... Kaut gan tie it kā būs 2 SQL pēc kārtas.. bet ni pie liela lietotāju skaita var notikt jebkas Edited October 9, 2006 by Delfins Link to comment Share on other sites More sharing options...
Roze Posted October 9, 2006 Author Report Share Posted October 9, 2006 A kāpēc burti neērti? Imho, HEX-ā ir OK. (7 simb -> 5 simb) Tas ir mobils pakalpojums līdz ar to switchoties no cipariem uz burtiem ir ķeska :) Es te skatos kaut ko par SELECT * ... FOR UPDATE; Ja tas nolockos MIN(id) ierakstu un citai konekcijai atgriezīs nākošo min(id) būs ideāli.. Link to comment Share on other sites More sharing options...
Delfins Posted October 9, 2006 Report Share Posted October 9, 2006 Roze, pārbaudiju savu variantu, strādā tā kā iecerēts (protams man nav nekādas pārbaudas, bet tas jau sīkums) <?php include 'dbconn.php'; $action = @ trim($_GET['action']); $new_id = 0; switch ($action) { case 'release' : $id = @ (int) $_GET['id']; if ($id) { $sql = 'insert into big_table(refid) values ('.$id.')'; $res = mysql_query( $sql, $link ); $sql = 'update small_table SET free=1 where id = '.$id; $res = mysql_query( $sql, $link ); } break; case 'reserve' : $sql = "select min(id) AS id from small_table where free = 1"; $res = mysql_query( $sql, $link ); $row = mysql_fetch_object($res); if ($row->id) { $sql = "update small_table SET free=0 where id = {$row->id}"; mysql_query( $sql, $link ); $new_id = $row->id; } else { $sql = "insert into small_table(free) values (0)"; mysql_query( $sql, $link ); $new_id = mysql_insert_id( $link ); } break; } if ($action) { header('Location: index.php?'); } ?> <a href="?action=reserve">Rezerveet ID</a> <? if ($new_id) { // Send SMS print "<p>Tavs jaunais ID ir `{$new_id}`.</p>"; } # Print `stack` table $sql = "select id, free from small_table"; $res = mysql_query( $sql, $link ); print '<hr />Stack table <table border="1">'; while ( $row = mysql_fetch_object($res) ) { print '<tr><td>'.$row->id.'</td>'; print (!$row->free) ? '<td><a href="?action=release&id='.$row->id.'">Izmantot</a></td>' : '<td>(briivs)</td>'; print '</tr>'; } print '</table>'; # Print `data` table $sql = "select id, refid from big_table"; $res = mysql_query( $sql, $link ); print '<hr />Data table <table border="1">'; while ( $row = mysql_fetch_object($res) ) { print '<tr><td>'.$row->id.'</td><td>REF: '.$row->refid.'</td></tr>'; } print '</table>'; ?> http://85.115.122.95/dbid/index.php? Link to comment Share on other sites More sharing options...
Roze Posted October 9, 2006 Author Report Share Posted October 9, 2006 Nja FOR UPDATE locko tikai uz update/delete ne SELECT (read). Delfins tavā variantā ir problēma: $sql = "select min(id) AS id from small_table where free = 1"; Kas notiek ja ienāk divas konekcijas reizē? Abas izpilda konkrēto selectu .. dabū vienādu 'id' un sākas šaize, jo $sql = "update small_table SET free=0 where id = {$row->id}"; izpildās vēlāk.. Proti starp pirmo selectu un updeito pa starpu (kas nomaina small_table konkrētā ID statusu) var notikt jau N identiski selecti kuriem tiks atgriezts identisks "mazais" id .. Vienkāršāk sakot ir problēma jo nav (vai es kaut kā nevaru atrast) row-level READ locks (es gan pieņemu varētu būt baigais overheds no servera puses ko tādu implementēt). Ideāli būtu: Konekcija1: SELECT min(id) From table lock read; id | 1 | Konekcija2: SELECT min(id) From table lock read; id | 2 | ... Link to comment Share on other sites More sharing options...
Grey_Wolf Posted October 9, 2006 Report Share Posted October 9, 2006 Proti lietotājam jāoperē ar ieraksta ID taču ?? Kaapeec lietotaajam vispaar buutu jaaredz ID? Manupraat tas nav isti korekti ... skjiet tomeer ka ID ir SQL "iekseejai lietoshanai" ??? Nevar to visu apiet un katram Lietotaajam pieskjirt Unikaalu vertiibu (kautvai skaitlis...) un no taa izejot veikt pieprasijumus.... (un tad jau po ka ID ir milziigs....) Godiigi sakot nevaru iedomaaties kur buutu nepiecieshams ar roku vadiit ieksaa ID .... (Piedevaam kursh ir tikai pagaidu???) --------------- Link to comment Share on other sites More sharing options...
PheliX Posted October 9, 2006 Report Share Posted October 9, 2006 nevar kautkā tā? update small_table set free = 0, @id = id where id = ( select min(id) AS id from small_table where free = 1 ); select @id as id; es nez tik vai tie updeiti nevar notikties vairāki reizē... Link to comment Share on other sites More sharing options...
Roze Posted October 9, 2006 Author Report Share Posted October 9, 2006 Kaapeec lietotaajam vispaar buutu jaaredz ID?Manupraat tas nav isti korekti ... skjiet tomeer ka ID ir SQL "iekseejai lietoshanai" ??? Nevar to visu apiet un katram Lietotaajam pieskjirt Unikaalu vertiibu (kautvai skaitlis...) un no taa izejot veikt pieprasijumus.... (un tad jau po ka ID ir milziigs....) Godiigi sakot nevaru iedomaaties kur buutu nepiecieshams ar roku vadiit ieksaa ID .... (Piedevaam kursh ir tikai pagaidu???) --------------- šoreiz ID nav jāsaprot obligāti kā tabulas relācijas lauks bet gan vienkārši unikāls keywords ar ko operē lietotājs. Nu minēšu piemēru - apmaksa ar SMS .. tev patīk rakstīt sms ar 8 ciparu skaitļiem un nedod dies nenokļudīties? update small_table set free = 0, @id = id where id = ( select min(id) AS id from small_table where free = 1 );select @id as id; Patestēsim.. bet ienāca šāda doma prāta. Ir gan zināms overheads bet varētu atrisināt konkurences un lockošanas problēmas, proti daram šādi. 1. Iegūstam lielais_id = mysql_insert_id(); 2. UPDATE small_table SET bigid = 'lielais_id', free = 0 WHERE free = 1 LIMIT 1 (Sheit LIMIT 1 garantee ka tiks updeitots tikai viens ieraksts.. ) 3. Un tad SELECT id FROM small_table WHERE bigid = 'lielais_id' Otrajā punktā var vēl checkot ja affected rows ir 0 tad var taisīt INSERT (nu teiksim small_table ir izbeigušies visi mazie ID cipari). Link to comment Share on other sites More sharing options...
Delfins Posted October 9, 2006 Report Share Posted October 9, 2006 1.) Roze, to select + lock for update, sauc par isolation_level (es nezinu vai MYSQL tāds ir). 2.) neviens tev neliedz updeitot ar pārbaudi function recursive_getid() { $ID = select min(id) ... sql = update small_table set FREE = 1 where ID = $ID AND free = 0 if (!$affected_rows) { return recursive_getid(); } return $ID; } Līdzīgi strādā Deadlock mehānisms ... taisa RETRY(rekursīvā izpilde) 3.) Grey_Wolf, problēma nav tajā, kā dabūt ciparu, bet tur, ka jūzeram jāievada garš simbols... pieļauju ka šis te tiks izamntots draugiem.lv un lietotāju pieprasījumu skaits liels, attiecīgi `SMS: DARI_SITO 2423423123 ` ir ļoti neerts... Link to comment Share on other sites More sharing options...
Roze Posted October 9, 2006 Author Report Share Posted October 9, 2006 1.) Roze, to select + lock for update, sauc par isolation_level (es nezinu vai MYSQL tāds ir).Jā ir.. 2.) neviens tev neliedz updeitot ar pārbaudi Ja protams taču caveats ir tas SELECT min(ID) .. 3.) Grey_Wolf, problēma nav tajā, kā dabūt ciparu, bet tur, ka jūzeram jāievada garš simbols... pieļauju ka šis te tiks izamntots draugiem.lv un lietotāju pieprasījumu skaits liels, attiecīgi `SMS: DARI_SITO 2423423123 ` ir ļoti neerts... Ne obligāti tur ;) Vienkārši ir diezgan daudz analogu pakalpojumu / risinājumu.. Mīnus ir gan ka papildus jātaisa kaut kāds history logs jo lietotājs vairs neoperē ar objekta īstajiem identifikatoriem bet gan temporāri piešķirtiem.. Link to comment Share on other sites More sharing options...
Delfins Posted October 9, 2006 Report Share Posted October 9, 2006 Nu kā, big_table saturēs id, user_id, ref_id, trans_date, trans_time, + papildus dati, kas bijā small_table nav uzlikta tilde, tāpēc nesaprotu, kas ir ... `caveats`... Katrā ziņā tā nebūs resurs-rijīga lieta... Jo ID būs tik daudz, cik būs konkurento lietotāju. parasti tā jau ir "Saņem ID, un uzreiz izmanto" (nezinu tieši kam tev vajag tos ID). Turklāt netiek veidota grupēšana, sortēšana... Gandrīz tas pats, kas pa `shared atmiņu` rakņāties :) Link to comment Share on other sites More sharing options...
e-remit Posted October 12, 2006 Report Share Posted October 12, 2006 Neiedziļinājos koda rindās, bet, nogurušām acīm lasot, ienāca doma. Table1 (id normals_id_lauks, uq_id unikals_pagaidu_id, citi_lauki). Tad nu redz - id netiek aiztikts, bet uz izmantošanas brīdi piešķir uq_id = minimālais pieejamais brīvais uq_id, bet pēc izmantošanas, uq_id = NULL. Ceru, ka domu uztvēri. Link to comment Share on other sites More sharing options...
Recommended Posts