MySQL - Unterschied zwischen der Verwendung von count (*) und information_schema.tables zum Zählen von Zeilen

15

Ich möchte auf schnelle Weise die Anzahl der Zeilen in meiner Tabelle mit mehreren Millionen Zeilen zählen. Ich fand den Beitrag " MySQL: Schnellster Weg, um die Anzahl der Zeilen zu zählen " in Stack Overflow, der anscheinend mein Problem lösen würde. Bayuah lieferte diese Antwort:

SELECT
    table_rows "Rows Count"
FROM
    information_schema.tables
WHERE
    table_name="Table_Name"
AND
    table_schema="Database_Name";

Was mir gefallen hat, weil es aussieht wie ein Lookup anstelle eines Scans, also sollte es schnell gehen, aber ich habe mich entschlossen, es zu testen

SELECT COUNT(*) FROM table 

um zu sehen, wie groß der Leistungsunterschied war.

Leider erhalte ich unterschiedliche Antworten, wie unten gezeigt:

Bildbeschreibung hier eingeben

Frage

Warum unterscheiden sich die Antworten um ungefähr 2 Millionen Zeilen? Ich vermute, dass die Abfrage, mit der ein vollständiger Tabellenscan durchgeführt wird, die genauere Nummer ist. Gibt es jedoch eine Möglichkeit, die richtige Nummer zu ermitteln, ohne diese langsame Abfrage ausführen zu müssen?


Ich lief ANALYZE TABLE data_302, was in 0,05 Sekunden abgeschlossen ist. Wenn ich die Abfrage erneut ausführe, erhalte ich jetzt ein viel genaueres Ergebnis von 34384599 Zeilen, aber es ist immer noch nicht dieselbe Nummer wie select count(*)bei 34906061 Zeilen. Gibt die Analysetabelle sofort zurück und wird im Hintergrund verarbeitet? Ich denke, es ist erwähnenswert, dass dies eine Testdatenbank ist und derzeit nicht geschrieben wird.

Es wird niemanden interessieren, ob es nur darum geht, jemandem zu sagen, wie groß eine Tabelle ist, aber ich wollte die Zeilenzahl an einen Code übergeben, der diese Zahl verwendet, um "gleich große" asynchrone Abfragen zum Abfragen der Datenbank zu erstellen Parallel dazu, ähnlich der in Erhöhen der langsamen Abfrageleistung mit der parallelen Abfrageausführung von Alexander Rubin gezeigten Methode . So wie es ist, werde ich nur die höchste ID mit bekommen SELECT id from table_name order by id DESC limit 1und hoffe, dass meine Tabellen nicht zu fragmentiert werden.

Programster
quelle

Antworten:

23

Es gibt verschiedene Möglichkeiten, Zeilen in einer Tabelle zu "zählen". Was am besten ist, hängt von den Anforderungen ab (Genauigkeit der Zählung, wie oft wird ausgeführt, ob die gesamte Tabelle gezählt werden muss oder mit Variablen whereund group byKlauseln usw.).

  • a) den normalen Weg. Zähle sie einfach .

    select count(*) as table_rows from table_name ; 

    Genauigkeit : 100% genaue Zählung zum Zeitpunkt der Ausführung der Abfrage.
    Effizienz : Nicht gut für große Tische. (Für MyISAM-Tabellen ist es spektakulär schnell, aber niemand verwendet MyISAM heutzutage, da es so viele Nachteile gegenüber InnoDB hat. Das "spektakulär schnelle" gilt auch nur, wenn die Zeilen einer gesamten MyISAM-Tabelle gezählt werden - wenn die Abfrage eine WHEREBedingung hat, dann muss immer noch die Tabelle oder einen Index
    durchsuchen .) Bei InnoDB-Tabellen hängt dies von der Größe der Tabelle ab, da die Engine entweder die gesamte Tabelle oder einen gesamten Index durchsuchen muss, um die genaue Anzahl zu ermitteln. Je größer der Tisch, desto langsamer wird es.

  • b) mit SQL_CALC_FOUND_ROWSund FOUND_ROWS(). Kann anstelle des vorherigen Weges verwendet werden, wenn wir auch eine kleine Anzahl der Zeilen wollen (Ändern der LIMIT). Ich habe gesehen, dass es zum Blättern verwendet wird (um einige Zeilen abzurufen und gleichzeitig zu wissen, wie viele int total sind und die Anzahl der Pgegs zu berechnen).

    select sql_calc_found_rows * from table_name limit 0 ; 
    select found_rows() as table_rows ;

    Genauigkeit : wie zuvor.
    Effizienz : wie zuvor.

  • c) Verwenden der information_schemaTabellen als verknüpfte Frage:

    select  table_rows
    from    information_schema.tables
    where   table_schema = 'database_name'
      and   table_name = 'table_name' ;

    Genauigkeit : Nur eine Annäherung. Wenn die Tabelle das Ziel häufiger Einfügungen und Löschungen ist, kann das Ergebnis weit von der tatsächlichen Anzahl entfernt sein. Dies kann durch ANALYZE TABLEhäufigeres Ausführen verbessert werden .
    Effizienz : Sehr gut, es berührt den Tisch überhaupt nicht.

  • d) Speichern des Zählers in der Datenbank (in einer anderen "Zähler" -Tabelle ) und Aktualisieren dieses Werts jedes Mal, wenn die Tabelle ein Einfügen, Löschen oder Abschneiden aufweist (dies kann entweder mit Triggern oder durch Ändern der Einfügungs- und Löschprozeduren erreicht werden). .
    Dies wird natürlich eine zusätzliche Last in jedes Einfügen und Löschen einbringen, liefert aber eine genaue Zählung.

    Genauigkeit : 100% genaue Zählung.
    Effizienz : Sehr gut, muss nur eine einzelne Zeile aus einer anderen Tabelle lesen.
    Es belastet jedoch die Datenbank zusätzlich.

  • e) Speichern ( Zwischenspeichern ) der Zählung in der Anwendungsschicht - und Verwenden der 1. Methode (oder einer Kombination der vorherigen Methoden). Beispiel: Führen Sie alle 10 Minuten die Abfrage der genauen Anzahl durch. Verwenden Sie in der Zwischenzeit zwischen zwei Zählungen den zwischengespeicherten Wert.

    Genauigkeit : Annäherung, aber unter normalen Umständen nicht zu schlecht (außer wenn Tausende von Zeilen hinzugefügt oder gelöscht werden).
    Effizienz : Sehr gut, der Wert ist immer verfügbar.

ypercubeᵀᴹ
quelle
1

Für INNODBSie information_schema.INNODB_SYS_TABLESTATS.NUM_ROWSgenaue Tabellenzeile Zähldaten für, statt information_schema.TABLES.TABLE_ROWS.

Ich habe hier weitere Details gepostet: /programming/33383877/why-does-information-schema-tables-give-such-an-unstable-answer-for-number-of-ro/49184843#49184843

Rob Bradshaw
quelle
1
Falsche Informationen ... "Für INNODB möchten Sie information_schema.INNODB_SYS_TABLESTATS.NUM_ROWS für eine genaue Tabellenzeile:" Das Handbuch sagt eindeutig geschätzt auf die NUM_ROWSSpalte
Raymond Nijland