dalsi hlavolam WAS: jak z toho ven

Petr Vileta petr na practisoft.cz
Sobota Červen 28 01:57:55 CEST 2003


"Petr Vileta" <petr na practisoft.cz> píše v diskusním příspěvku
news:bdg7uv$2rn2$4 na ns.felk.cvut.cz...
> Jsem ve fazi testovani a narazil jsem na dalsi problem. Zadavatel si nedal
> vysvetlit, ze by si login meli urcovat sami soutezici, neakceptoval ani
> pismena a navic si TED vymyslel, ze to musi byt cisla z rozsahu 100001 az
> 999999, ovsem generovana NAHODNE. Je to normalni reklamni trik (jak tvrdi
> zadavatel) nebo podvod (jak tvrdim ja), aby ucastnici nepoznali kolik jich
> vlastne celkem je a tudiz jaka je sance na vyhru. Jenze generovat neco
> takoveho je silenost, tak me napadlo, ze bych si ta cisla vygeneroval
> jednorazove predem do tabulky:
> id mediumint(6), pouzito smallint(1)
> a pak jen delal:
> SELECT id FROM cisla WHERE pouzito=0 limit 1;
> Sice to bude tabulka jako krava, ale bude to rychle pri tom pridelovani
id.

Provedl jsem si testy a dospel k zajimavemym poznatkum, tak tady jsou.
Zkousel jsem vytvorit tabulku

create table cisla (idnum mediumint(6) unsigned not null primary key,
pouzito datetime, karantena date);

a do ni generovat rand() cisla upravena na rozsah 100001 az 999999. Spustil
jsem skript, ktery generoval 800000 zaznamu a na stdout vypisoval cas
potrebny k jednomu zapisu. Vypadal asi nejak takhle

for($pocet=1; $pocet <= 80000; $pocet++)
    {
    &do_insert;
    }

sub do_insert
{
    $q=0;
    $t1=time;
    while($q < 80000)
        {
        $err=0;
        $idnum=genrand(100001,999999);
        $sth=$dbh->prepare("insert into cisla set idnum=$idnum");
        $sth->execute() or $err=1;
        $sth->finish;
        if($err==0)
            {
            print "time - $t1\n";
            return;
            }
        $q++;
        }
}
sub genrand
{
return int(($_[1]*1 - $_[0]*1 +1) * rand() + $_[0]*1);
}

Ze zacatku to bezelo samozrejme rychle, ale pak to zacalo postupne
zpomalovat a posledni zobrazena hodnota byla cca 12minut. Takze jsem tento
zpusob zavrhnul a vratil se k memu puvodnimu zameru, ze si vygeneruji
tabulku predem a budu jen "obsazovat" dosud nepouzite zaznamy. Tabulka
obsahuje 899998 cisel a ma i s indexy 30MB. Je vytvorena uplne stejne a
navic ma vytvorene 2 indexy z poli "pouzito" a "karantena".
Ted prideleni idnum probiha takto

# zamkneme, aby nam to nekdo nevzal pod rukama
$sth=$dbh->do("lock tables soutez_cisla write");
# najdeme prvni volne cislo, ktere jeste nebylo nikdy pouzito
$sth=$dbh->prepare("select idnum from soutez_cisla
     where isnull(karantena) and isnull(prideleno) limit 0,1");
$sth->execute() or die "can't select free idnum";
$q=$sth->rows*1;
if($q==1)
 {
# pokud se cislo naslo, nacteme ho
 $row=$sth->fetchrow_arrayref;
 $idnum=$row->[0]*1;
 $sth->finish;
# a zapiseme, ze uz je pouzite
 $sth=$dbh->prepare("update soutez_cisla set prideleno=now() where
idnum=$idnum");
 $sth->execute() or die "can't update soutez_cisla";
 $sth->finish;
# a sammozrejme odemkneme
 $sth=$dbh->do("unlock tables");
# uspech, vracime se
 return 0;
 }
$sth->finish;
# najdeme prvni volne cislo, ktere je v karantene dele nez 1 rok
$sth=$dbh->prepare("select idnum from soutez_cisla
     where not isnull(karantena) and karantena*1 < date_sub(now(), interval
1 year)*1
     limit 0,1");
$sth->execute() or die "can't select any idnum";
$q=$sth->rows*1;
if($q==1)
 {
# pokud jsme nasli, tak ho nacteme
 $row=$sth->fetchrow_arrayref;
 $idnum=$row->[0]*1;
 $sth->finish;
# a zapiseme, ze uz je pouzite, zaroven nastavime karantenu na null
 $sth=$dbh->prepare("update soutez_cisla set prideleno=now(), karantena=null
where idnum=$idnum");
 $sth->execute() or die "can't update soutez_cisla";
 $sth->finish;
# a sammozrejme odemkneme
 $sth=$dbh->do("unlock tables");
# take uspech, tak zpatky
 return 0;
 }
$sth->finish;
# nepodarilo se tak ani tak, ale musime odemknout
$sth=$dbh->do("unlock tables");
return 14; # neni mozne pridelit dalsi cislo, vraci se error 14

Na tenhle program je odezva na prideleni idnum maximalne 5 sekund.

Testovano (oboji) na singl stroji s jedinym aktivnim klientem.
--
Petr




Další informace o konferenci Databases