Anzahl an Datensätzen eines SQL-Results ermitteln

Dies ist ein Gastbeitrag von Stefan Riedinger.

Oft braucht man die Anzahl der vorhanden Datensätze eines Result-Sets – zum Beispiel für Statistiken, in denen man angeben möchte wie viele Datensätze es in dem Projekt gibt. Dieser Beitrag untersucht die Möglichkeiten die Anzahl der Datensätze zu ermitteln.

Grundsätzlich gibt es zwei Möglichkeiten, die hier nun vorstellt und verglichen werden sollen:

  1. Wir selektieren ein beliebiges Element der Tabelle oder eine Kontante, führen den SQL-Befehl mitsamt WHERE-Bedingung normal aus und lassen mysql_num_rows() die Anzahl der Datensätze ermitteln.
    In Code:

    $result = mysql_query("SELECT 1 FROM tabelle WHERE spalte='123'");
    echo mysql_num_rows($result);
  2. Wir benutzen in SQL die count-Funktion
    In Code:

    $result = mysql_query("SELECT COUNT(*) FROM tabelle WHERE spalte='123'");
    echo mysql_result($result,0);

Meine erste Überlegung war nun, das mysql_num_rows() schneller sein wird, da diese Funktion speziell für das Auswerten der Anzahl der Datensätze ist.
Ich habe nun einen kleinen Test gestartet, in dem ich die beiden Methoden miteinander verglichen habe.
Die Datenbank hatte im Test 678 Datensätze und der Befehl wurde 1000 mal ausgeführt um eine Durchschnittszeit zu errechnen.

1. Methode
Durchschnitt: 0.51376736474 ms

2. Methode
Durchschnitt: 0.0429143209457 ms

Das Ergebnis zeigt, das die zweite Methode rund 12mal schneller ist. Für jemanden, der etwas tiefer in der Materie steckt, sollte das Ergebnis nicht überraschend sein.

Bei der ersten Methode werden alle Elemente, die sich in der Datenbank befinden, selektiert und an PHP übergeben, die Funktion mysql_num_rows() wertet nun die Anzahl der Datensätze aus.
Dies macht die ganze Sache natürlich etwas langsamer, wie man es an dem Test gemerkt hat.

Die zweite Methode hingegen sendet von dem Datenbanksystem nur eine Zahl, nämlich die Anzahl der Datensätze. Das Zählen übernimmt hier SQL. Der Traffic zwischen PHP und MySQL ist somit viel geringer (und wächst vor allem nicht mit der Anzahl der Datensätze -> Komplexität O(1) ).

Ich frage mich nun aber nach dem Einsatzbereich von mysql_num_rows(), für das Zählen ist diese Funktion ungeeignet, da sie viel zu langsam ist.
Vielleicht weiß ja jemand von den Lesern einen guten Grund um mysql_num_rows() anzuwenden.

Anmerkung von daryl: Eine Ursache für den massiven Geschwindigkeitsunterschied könnte auch das Query Caching sein, denn MySQL cacht die Queries ja und somit bleibt auf PHP-Seite trotzdem noch der Aufwand des Zählens per mysql_num_rows().
Einen sinnvollen Einsatzzweck für mysql_num_rows() sieht man beispielsweise in meinem vorherigen Beitrag.

Interessant wäre noch der Unterschied zwischen COUNT(*) gegen COUNT(Primary_key_spalte). Vielleicht kannst Du das noch testen.

Jan hat 152 Beiträge geschrieben

15 Kommentare zu “Anzahl an Datensätzen eines SQL-Results ermitteln

  1. Jo sagt:

    Danke für den Beitrag!
    mysql_num_rows() ist z.b. nützlich, wenn man das Resultset sowieso benötigt:

    [code]PGNvZGU+DQokcmVzdWx0ID0gbXlzcWxfcXVlcnkoLi4uKTsNCndoaWxlICgkcm93ID0gLi4uLikgew0KICBlY2hvIFwiLi4uXCI7DQp9DQppZiAobXlzcWxfbnVtX3Jvd3MoJHJlc3VsdCkgPT0gMCkgew0KICBlY2hvIFwia2VpbmUgRWludHLDpGdlXCI7DQp9DQo8L2NvZGU+[/code]

    Interessant wäre, ob ein SELECT COUNT(*) und ein nachfolgender „normaler“ Query schneller wären als ein mysql_num_rows() – was aber wahrscheinlich stark vom Query abhängt.
    Oder ob eine Zählvariable ($1++ bei jedem Durchlauf) schneller ist, die man dann nach der Schlaufe auf den Wert überprüft… (wenn $i immer noch 0 = keine Einträge) oder was gibts sonst noch für Möglichkeiten? So eine „Total xx Einträge“ nach der Ausgabe des Resultsets benötige ich noch oft.

  2. kb sagt:

    Evtl. ist ja mysql_num_rows angebracht, wenn man mit dem Datensatz weiterarbeitet.Wenn der Datensatz sowieso geholt wird, um ihn zu durchlaufen, kann man auch gleich von dort die Anzahl ermitteln (z.b. fiktives Szenario: Kommentare zu einem Beitrag, da steht ja auch oft wie viele es gibt) und man muss nicht einen zusätzlichen Datensatz anfordern.

  3. Florian sagt:

    Die Ergebnisse stehen sehr konträr zum vergangenen Artikel, wo prinzipiell dasselbe bereits getestet wurde.

    Man sollte sich, bevor man den Artikel online stellt, untereinander absprechen. Nicht, dass dieser Artikel schlecht wäre, doch kann man ihn in dieser Form nicht bringen, wenn man selbigen vor ein paar Wochen mit völlig anderen Ergebnissen dem User präsentiert hat.

    Ich würde mich freuen, wenn an dieser Stelle noch einmal ausgiebig getestet werden würde, so dass man zu einem finalen Ergebnis käme.

  4. admin sagt:

    @Florian: Nö, sind nicht konträr. Genau genommen, habe ich die Aussagen dieses Beitrags hier in meinem letzten Beitrag bereits erwähnt:
    —-
    Die schnellste Variante ist demzufolge das Zählen von PHP erledigen zu lassen – per mysql_num_rows(). Die anderen beiden Varianten haben aber Ihre Vorteile, wenn man nicht nur auf das Vorhandensein eines einzelnen Datensatzes prüft, sondern eine große Datenmenge hat. Dann würde das Zählen von MySQL die von PHP auszuwertende Datenmenge nämlich beträchtlich senken.
    —-
    Man muss also unterscheiden, ob man prüfen möchte, ob ein bestimmter Datensatz existiert oder eine Menge von Datensätzen gezählt werden soll.

  5. Alex sagt:

    Der Trend geht klar mit der Performance. Lieber alles die Datenbank machen lassen, der Apache hat bei Hochkonjuktur eh genug zu tun xD.

    Gruß Alex

  6. SeeeD sagt:

    Hi,

    ich bin der Autor dieses Artikels.
    Morgen werde ich verschiedene andere Möglichkeiten mit aufnehmen und ausprobieren.
    Ich werde euch die Ergebnisse mitteilen.

    Ich habe diesen Artikel an den Admin gesendet, da ich hier gerne Beiträge lese, aber leider sehr selten neue Beiträge erscheinen.
    Deswegen dachte ich mir ich arbeite mal ein kleines Thema aus.

    Schönen Abend noch 😉

  7. Es ist etwas schwierig zu sehen, was Du da genau misst. Man kann schlecht ein mysql_result mit mysql_num_rows vergleichen bzw. die beiden Querys sind ja doch recht unterschiedlich, wenn Du die mit rein nimmst.

    Ich empfinde es so, als wenn hier Äpfel und Birnen verglichen werden.

    Das SELECT Feld muss ja bei weitem mehr tun als ein SELECT COUNT(*). Das COUNT ist immer sehr schnell, gerade wenn Du für die WHERE Klausel Indizes hast und das Resultset ist nur ein Feld. Das andere Resultset sind dann alle 678 Datensätze.

    Ein EXPLAIN sollte das vielleicht zeigen können.

    Wenn ich nur mysql_result und mysql_num_rows allein mit microtime messe, dann sind beide auf meinem Server bei 5.9605E-6 also unglaublich schnell.

    Benchmarken könnte man sonst ein Konstrukt aus COUNT Query + richtiges SELECT, gegen SELECT und num_rows?

    Schreib doch nochmal genau was Du misst. Ansonsten würde ich mir keine Sorgen machen wie schnell mysql_result ist.

    Gruß,
    Karsten

  8. cinteX sagt:

    mysql_num_rows() ist in der hinsicht nützlich, dass man einen query ausführt, obgleich dieser leer ist oder nicht.

    mit mysql_num_rows() kann man dann im endeffekt einfach prüfen ob datengeholt wurden, wieviele geholt wurden etc. und hat trotzdem noch die daten des eigentlichen queries

  9. Fred sagt:

    Danke für den Artikel.
    Nachdem ich meine Website komplett neugeschrieben habe, habe ich festgestellt, dass das Zufallsbild eine extreme Bremse ist.

    Es ist eine Zeltlagerseite, und dort wird bei jedem Aufruf ein zufälliges Bild angezeigt, also eine Zufallszahl zwischen 1 und der Anzahl der Datensätze ausgesucht.
    Mittlerweile sind das aber ca. 5000 Datensätze, die bei jedem Seitenaufruf per mysql_num_rows gezählt werden.

    Ich werde es gleich mal überarbeiten, vielen Dank 🙂

  10. Daniel sagt:

    Hallo, habe grad die 2 beispiele getestet, bei mir tut das nicht!

    Frage:
    Wo kommt plötzlich die variable $einlesen her?
    echo mysql_result($einlesen,0);

    Bei mir funktioniert nur dieses Beispiel von mir:
    $all=mysql_query(„SELECT * FROM tab_pkw“,$conn);
    echo „Datensätze: „.mysql_num_rows($all);

    Das hier funktioniert nicht:
    $all=mysql_query(„SELECT COUNT (*) FROM tab_pkw“,$conn);
    echo „Datensätze: „.$all;
    …hier erscheint ganicht, auch keine fehlermeldung!

    Was mach ich da falsch?

  11. Jan sagt:

    Sorry, das $einlesen war falsch, habe es korrigiert.

    Was soll bei Deinem 2. Beispiel auch rauskommen? Die Rückgabe von mysql_query ist entweder ein ResultSet oder ein Boolean. Ein ResultSet kann man aber nicht einfach so ohne weiteres ausgeben, sondern nur per mysql_fetch_assoc oder ähnlichen Funktionen durchlaufen bzw. per mysql_num_rows oder mysql_result darauf zugreifen.

  12. Wörterbuch sagt:

    Nanu. Da versucht man SQL perfomanter zu gestalten; verwendet Tage, um eine effiziente Indizierung zu erreichen. Aber an diesen „Booster“ habe ich noch nicht gedacht!
    Gute Arbeit und vielen Dank.

  13. Felix sagt:

    Auch wenn schon ein etwas älterer Beitrag, trotzdem vielen dank dafür!

    Stand jetzt gerade selbst vor der Entscheidung, was sinnvoller ist. In meinem Fall möchte ich große Suchergebnisse auf mehreren, kleineren Seiten aufteilen.
    Dort ist für mich die Gesamtzahl der Datensätze bereits vor deren Abruf interessant… meist benötige ich nämlich nur einen Bruchteil aller dieser Daten.
    Wozu dann also erst alle Daten selektieren und abrufen um sie zu zählen? Hab‘ mir dann auch überlegt das mittels COUNT zu implementieren und war mir aber nicht sicher, ob ich damit wirklich besser fahre… jetzt bin ich aber überzeugt 🙂

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>