Hlavní navigace

PHP okénko: Získání počtu řádek

Jakub Vrána 30. 3. 2005

Druhý díl PHP okénka přináší drobný postřeh z programování v PHP, který se týká možných způsobů získání počtu řádek databázové tabulky.

Často je potřeba získat počet řádek, které obsahuje databázová tabulka. A jako obvykle k tomu vede více cest.

<?php
// neefektivní
$pocet = mysql_num_rows(mysql_query("SELECT * FROM tabulka"));

// rychlejší
$pocet = mysql_result(mysql_query("SELECT COUNT(*) FROM tabulka"), 0);
?> 

První způsob je neefektivní proto, že SQL server se připraví na to, že bude vracet všechna data z tabulky, a připraví si na to potřebné struktury. Druhý způsob je naproti tomu velice rychlý, protože MySQL jenom vezme počet řádků tabulky, který si vede jako statistický údaj, a vrátí ho. Funkci mysql_num_rows je vhodné použít pouze v případě, kdy data z tabulky budeme tak jako tak potřebovat, tedy např.:

<?php
$result = mysql_query("SELECT * FROM tabulka");
echo "Celkový počet záznamů: " . mysql_num_rows($result) . "\n";
while ($row = mysql_fetch_assoc($result)) {
    // zpracování tabulky
}
mysql_free_result($result);
?> 

Další problém je potřeba vyřešit v případě, kdy sice chceme zjistit celkový počet řádků tabulky, ale chceme jich vypsat jen několik.

<?php
// neefektivní
$pocet = mysql_result(mysql_query("SELECT COUNT(*) FROM tabulka /* WHERE složitá podmínka */"), 0);
$result = mysql_query("SELECT * FROM tabulka /* WHERE složitá podmínka */ LIMIT $limit OFFSET $offset");
while ($row = mysql_fetch_assoc($result)) {
    // zpracování řádku
}
mysql_free_result($result);

// taktéž neefektivní
$result = mysql_query("SELECT * FROM tabulka /* WHERE složitá podmínka */");
$pocet = mysql_num_rows($result);
if ($offset < $pocet) {
    mysql_data_seek($result, $offset);
    $i = 0;
    while ($row = mysql_fetch_assoc($result)) {
        // zpracování řádku
        $i++;
        if ($i >= $limit) {
            break;
        }
    }
}
mysql_free_result($result);

// elegantní, ale jde použít pouze v MySQL a to až od verze 4
$result = mysql_query("SELECT SQL_CALC_FOUND_ROWS * FROM tabulka /* WHERE složitá podmínka */ LIMIT $limit OFFSET $offset");
$pocet = mysql_result(mysql_query(" SELECT FOUND_ROWS()"), 0);
while ($row = mysql_fetch_assoc($result)) {
    // zpracování řádku
}
?> 

První způsob je neefektivní pro dotazy se složitými podmínkami (např. vyhledávání podle masky) nebo složitě spojující více tabulek, druhý způsob je neefektivní pro vysoký $offset. To, že je úloha získání celkového počtu řádků společně s vrácením jen několika z nich poměrně častá, si v MySQL uvědomili a nabídli pro ni efektivní, byť nestandardní řešení. Pokud ale aplikace nemusí pracovat nad více databázemi zároveň, není důvod se mu bránit.


Podobně laděné texty můžete najít i na autorově weblogu PHP triky.

Našli jste v článku chybu?

30. 3. 2005 1:22

No mozna, ze MySQL to ma optimalizovano lepe nez tvoje oblibena databaze (protoze MySQL je optimalizovane kvalitne), ale bez ohledu na databazi bude druha moznost rychlejsi. PHP totiz implicitne pri mysql_query (narozdil od mysql_unbuffered_query) poctive precte celou odpoved SQL serveru a obavam se, ze stejne se chovaji i ostatni databazova rozhranni.
BTW, SQL server muze byt umisten i na jinem stroji nez apache - takze tahani vysledku muze zatizit i sit.

30. 3. 2005 1:33

uživatel si přál zůstat v anonymitě
Nikdy jsem netvrdil, že bude rychlejší první možnost! Nebude, zcela samozřejmě. Ale tvrzení, že „to bude rychle, protože MySQL si to ukládá bokem průběžně“ je jednak MySQL-specific (což v „PHP okénku“ zamrzí), jednak stále ještě netuším, jak je to s concurrency a transakcemi. Jakmile mám snapshot transakce, můžu mít tolik různých počtů řádek, kolik mám transakcí, že...

Tohle absolutně nemá co dělat s optimalizací databáze, spíš s jejím „přihýbáním“ některým t…

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře

Lupa.cz: Seznam mění vedení. Pavel Zima v čele končí

Seznam mění vedení. Pavel Zima v čele končí

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

DigiZone.cz: Recenze Prostřeno: cirkus postižených

Recenze Prostřeno: cirkus postižených

Vitalia.cz: Manželka je bio, ale na sex moc není

Manželka je bio, ale na sex moc není

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET

Vitalia.cz: Často čůrá a má žízeň? Příznaky dětské cukrovky

Často čůrá a má žízeň? Příznaky dětské cukrovky

Vitalia.cz: Dáte si jahody s plísní?

Dáte si jahody s plísní?

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Podnikatel.cz: Chtějte údaje k dani z nemovitostí do mailu

Chtějte údaje k dani z nemovitostí do mailu

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

DigiZone.cz: Sat novinky: slovenská TV8 HD i ruský NTV Mir

Sat novinky: slovenská TV8 HD i ruský NTV Mir

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

Vitalia.cz: Chtějí si léčit kvasinky. Lék je jen v Německu

Chtějí si léčit kvasinky. Lék je jen v Německu

Měšec.cz: Za palivo zaplatíte mobilem (TEST)

Za palivo zaplatíte mobilem (TEST)

Měšec.cz: Přejete si číslo účtu na přání?

Přejete si číslo účtu na přání?

Root.cz: Certifikáty zadarmo jsou horší než za peníze?

Certifikáty zadarmo jsou horší než za peníze?

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte