Iškilo būtinybė uždėti limitą duombazės dydžiui. Pats tokio funkcionalumo neturi. Ieškojau kaip išspręsti šią problemą… Mano reikalavimai sprendimui tokie:

  • reikalavimų minimumas; portabilumas - kad nereikėtų įdiegti papildomos programinės įrangos, kad veiktų kuo įvairesnėse aplinkose, nereikalautų didelio paruošimo bei palaikymo;
  • resursų taupymas


Kaip gali būti realizuota tokia funkcija? Atrodo pakankamai paprastai - tereikia žinoti duombazės dydį (esamą.. bet geriau tą, kuris būtų po užklausos įvykdymo) ir jei tas dydis viršija mūsų nustatytą limitą tai atitinkamai arba leidžiama įvykdyti užklausą arba ne.

Bet yra ir kitas būdas. Žinome, kad kiekvieną duombazę saugo atskirame kataloge. Taigi tereiktų failų sistemos lygyje nustatyti apribojimą tam katalogui, kad nesipūstų per daug. GNU/Linux sistemoje yra tokia galimybė nustatyti limitą konkrečiam naudotojo namų katalogui. Taigi:

  • sukuriam naują vartotoją (tebūnie ‘manovardas’) serveryje ir nustatom limitą jo namų katalogui.
  • sukuriam naują duombazę:
    CREATE TABLE manodb
  • sustabdom servisą - nebūtina, bet labai rekomenduojama!
  • perkeliam duombazės katalogą pas naudotoją “į namus”:
    mv /var/lib//manodb /home/manovardas

    (gal reikia “-R” rakto, nepamenu)

  • sukuriam nuorodą:
    ln -s /home/manovardas/manodb /var/lib//manodb
  • paleidžiam servisą.

Viskas. Ar šis sprendimas tinka visada? Nemanau. Pavyzdžiui, mes nežinom, kas bus, kai duombazė pasieks tą nustatytą limitą? Ar mums vykdant “insert” užklausą bus išmesta klaida? Ar viskas užstrigs? Servisas nulūš? Internete radau kažkieno pasakymą, kad tokiu atveju lūžta einamoji serviso gija. Visgi man sunku tuo patikėt - kai man pačiam buvo pasibaigus vieta particijoj ir įterpinėjau duomenis tai tiesiog mano užklausa užšaldavo. Kiti susijungimai toliau leisdavo vykdyt SELECT užklausas. Sako, tyla gera byla, bet mūsų atveju geriau būtų klaida :) dabar sėdi naudotojas ir nežino kas vyksta. Kita problema - reikia turėti teises į failų sistemą. Dar reikia kurti papildomą sistemos naudotoją… taigi, man šis sprendimas netiko, todėl ieškojau kaip realizuot pirmu minėtu metodu (patikrinant dydį).

Duombazės dydis - kaip jį sužinoti?

Turbūt paprasčiausia būtų pažiūrėt, kiek užima duombazės failai. Bet ne visada galim turėt galimybę tai atlikt. Pavyzdžiui, jei jungiamės prie nutolusio serverio. Arba net jei tai vietinis serveris, vis tiek galime neturėti teisių tokiam veiksmui.

Suskaičiuoti visus įrašus… mm.. būtų galima bandyt, jei kiekvienas įrašas užimtų tiek pat vietos - tada apskaičiuotume įrašo dydį, sudaugintume su eilučių skaičiumi lentelėje ir tai pakartotume visoms lentelėms. Bet, deja, ne visi įrašai yra fiksuoto dydžio - kaltininkai čia būtų VARCHAR (ir kt.) laukai. Taigi, pamirštam.

Atrodo yra paprastesnis būdas. Tai, ko mums reikia, grąžina užklausa:

SHOW TABLE STATUS;

Kad nesikartočiau, ką jau kažkas parašė, siūlau tiesiog užeit šiuo adresu:
http://www.drquincy.com/resources/tutorials/webserverside/getthesizeofamysqldatabasewithphp/

Limitai

Žinom duombazės dydį - kas dabar? Sakykim, mūsų sistema, kuri naudos duombazę, yra svetainė rašoma su PHP. Tai nejau prieš kiekvieną užklausą vykdysim tą kodą, kuris tikrina dydį? Jei mums reikės padaryt 10 000 įterpimų, tai tiek kartų tikrinti būtų neracionalu. Ypač jei klientas ir serveris yra nutolę. Kita problema - gal mes norime kad ne tik php skriptas įterpinėjant duomenis neperžengtų ribos, bet kad niekaip nebūtų įmanoma apeiti limito (net tiesiai prisijungus iš konsolės)? Tada reiktų tikrinimą kažkaip “įklijuoti” į patį . Taip ir padarom:

  • sukuriam funkciją (kažkas tokio kaip , tik grąžins skaičių) kuri nustato dydį
  • ant kiekvienos lentelės sukuriam trigerius, kurie suveiktų, pavyzdžiui, prieš įterpimą; trigeris turėtų patikrinti ar galima įterpti, ar ne.

Atrodo gražu, bet viena problemėlė. O kaip mes trigeryje pasakysim “žinai, nebedarom įterpimo nes pasiektas limitas”? neturi tokios galimybės kaip kad “raise_error” ant Microsoft Server. Sako, kad nuo 5.2 gal jau bus “signalai”, kurie leis padaryt tai, ko mums reikia.. bet mums reikia dabar. Visgi yra sprendimas:
http://www.brokenbuild.com/blog/2006/08/15/mysql-triggers-how-do-you-abort-an-insert-update-or-delete-with-a-trigger/
Siūlo tiesiog sukelti bet kokią kitą klaidos situaciją, pvz “unknown column”.

Beliko viską realizuot. Kadangi aš beveik nesu rašęs saugomų procedūrų (”“), funkcijų tai neišsiverčiau be dokumentacijos ir kodo pavyzdžių, rastų internete. Pavyzdžiui, štai kaip reiktų prasukt ciklą pasinaudojant kursoriais:
http://dev.mysql.com/doc/refman/5.0/en/cursors.html
Man šitas ciklas pasirodė keistokas, todėl dariau taip kaip parodyta čia:
http://www.futhark.ch/mysql/130.html

Viskas, daugiau paaiškinimų nebebus.

Funkcijos, nustatančios dydį, kodas:

delimiter //
CREATE FUNCTION dbsize () RETURNS integer
READS SQL DATA
BEGIN
  DECLARE size integer DEFAULT 0;
  DECLARE c1, c2, c3, c4, c5, c6,
    datalength, c8, indexlength,
    c10, c11, c12, c13, c14, c15, c16,
		c17, c18 integer;
  DECLARE done BOOLEAN DEFAULT FALSE;
 
  DECLARE curr CURSOR FOR SHOW TABLE STATUS;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = TRUE;
 
  OPEN curr;
 
  loop1: LOOP
 
    FETCH curr INTO c1, c2, c3, c4, c5, c6, datalength, c8, indexlength, c10, c11, c12, c13, c14, c15, c16, c17, c18;
    IF done THEN LEAVE loop1; END IF;
    SET size := size + datalength + indexlength;
 
  END LOOP loop1;
 
  CLOSE curr;
 
  RETURN size;
 
END;
//
delimiter ;

Trigerio kodas:

delimiter //
CREATE TRIGGER t1bi
BEFORE INSERT ON t1
  FOR EACH ROW
BEGIN
  SET @dummy = 0;
  IF dbsize() > 20000 THEN
    SELECT Database_size_limit_reached INTO @dummy FROM t1;
  END IF;
END;
//
delimiter ;

Čia:

  • 20000 - skaičius 20000 rodo baitų kiekį, kurio negali peržengti duombazės dydis.
  • t1 - lentelė, kuriai kuriamas trigeris; reikėtų sukurti kiekvienai lentelei.
  • t1bi - kuriamo trigerio vardas (lentelės vardas plius pirmosios raidės iš “BEFORE INSERT”)

Dabar beliko sutvarkyt leidimus (angl. permissions). Naudotojui leisti tik SELECT, INSERT, UPDATE, DELETE, bet neleisti kurti/trinti (būtent trinti) funkcijų ir trigerių.

Išvados

Man šis sprendimas labai tinka nes:

  • nėra jokių papildomų reikalavimų, nereikia nieko papildomai įdiegti, kurti papildomų lentelių. Na gerai, yra reikalavimai - būtinas trigerių palaikymas bei lentelėse negali būti stulpelis pavadinimu “Database_size_limit_reached” :)
  • nors tenka kiekvienu įterpimu iš naujo patikrinti dydį, bet tai sąlyginai mažai resursų reikalaujantis procesas (pas mane tik ~10 lentelių o ne 200+), ir pasitelkus “STORED PROCEDURES” tikrinimas vyksta ne pas klientą o pačioje , nenaudojamas tinklo srautas.

Panašūs straipsniai


“Limituojam MySQL duombazės dydį su… pačiu MySQL” komentarų: 3

  1. Tomas Markauskas

    Šis sprendimas neveiks su InnoDB lentelėmis, kurios duombazės direktorijoje tesaugo tik lentelių struktūrą, o pačius duomenis kiša į vieną (ar daugiau) tablespace failą/-us, dažniausiai gulinčius šalia duombazės direktorijos (data direktorijoje).

  2. Raigedas

    ačiū už komentarą.

    Turėtų veikti ir su InnoDB (spėju, neperskaitei nuosekliai viso straipsnio), nes nepriklausomai nuo DB variklio tipo, “SHOW TABLE STATUS;” turėtų grąžinti tą patį. Neveiktų nebent tas būdas kur iš pradžių minėjau apie failų sistemos limitus.

  3. Algerdas

    o ne rimciau butu sistemine lentele su laukais:
    lenteles_pavadinimas // kaip ir viskas aisku
    lentele_patikrinta // talpina ar lentele jau suskaiciuota
    lenteles_dydis // talpina kiek lentele uzima

    toliau uztenka trigeryje patikrint ar lentele patikrinta ir perskaiciuot visus irasus arba padidint jei vyksta papildymas
    jei dadedamas indeksas ar daromas kompact, tai sis laukas igyja false ir perskaiciuojam

    tokiu budu pamatuti kiek dumbaze uzima uztektu atlikt select sum(lenteles_dydis)
    toks buda leistu gerokai sumazint lenteliu apimties paskaiciavimo kastus

Rašyti komentarą

Jūs privalote prisijungti jeigu norite rašyti komentarą.