[Datenbankoptimierung-count()] count() zählt die Anzahl der Zeilen

Inhaltsverzeichnis

1 Warum ist die Leistung von count(*) schlecht?

2 Optimieren Sie die Leistung von count(*).

2.1 Redis-Cache hinzufügen

2.2 Multithread-Ausführung

2.3 Join-Tabellen reduzieren

Leistungsvergleich verschiedener Verwendungen von 3 count


Datenbank: Mysql8、Die Speicher-Engine ist Innodb.

Normalerweise fragt die Paging-Schnittstelle die Datenbank zweimal ab: Beim ersten Mal werden bestimmte Daten abgerufen, beim zweiten Mal wird die Gesamtzahl der Datensatzzeilen abgerufen, und dann werden die Ergebnisse vor der Rückgabe integriert.

SQL zum Abfragen bestimmter Daten wie dieser weist keine Leistungsprobleme auf.

select id,name from user limit 1,20;

Aber eine andere SQL, die count(*) verwendet, um die Gesamtzahl der Datensatzzeilen abzufragen, weist eine schlechte Leistung auf. Zum Beispiel:

select count(*) from user;

Warum passiert das?

1 Warum ist die Leistung von count(*) schlecht?

In MySQL count(*)besteht die Funktion darin, die Gesamtzahl der in der Tabelle aufgezeichneten Zeilen zu zählen. Die count(*)Leistung steht in direktem Zusammenhang mit der Speicher-Engine, aber nicht alle Speicher-Engines weisen count(*)eine schlechte Leistung auf.

Die am häufigsten verwendeten Speicher-Engines in MySQL sind: innodbund myisam.

In myisam wird die Gesamtzahl der Zeilen auf der Festplatte gespeichert. Bei Verwendung von count(*) müssen Sie nur diese Daten ohne zusätzliche Berechnungen zurückgeben, sodass die Ausführungseffizienz sehr hoch ist.

InnoDB ist anders. Da es Transaktionen unterstützt und über MVCCeine Multiversions-Parallelitätskontrolle verfügt, kann die Anzahl der von derselben Abfrage-SQL zurückgegebenen Datensatzzeilen in verschiedenen Transaktionen zum gleichen Zeitpunkt ungewiss sein. Bei Verwendung von count(*) in innodb müssen die Daten Zeile für Zeile aus der Speicher-Engine gelesen und dann akkumuliert werden, sodass die Ausführungseffizienz sehr gering ist. Es ist in Ordnung, wenn die Datenmenge in der Tabelle klein ist. Sobald die Datenmenge in der Tabelle groß ist, wird die Leistung sehr schlecht, wenn die Innodb-Speicher-Engine count(*)-Statistiken verwendet.

2 Optimieren Sie die Leistung von count(*).

2.1 Redis-Cache hinzufügen

Für eine einfache Zählung (*), z. B. das Zählen der Gesamtzahl der Aufrufe oder der Gesamtzahl der Besucher, können wir die Schnittstelle mithilfe von Redis direkt zwischenspeichern, ohne dass eine Echtzeitzählung erforderlich ist.

Wenn der Benutzer die angegebene Seite öffnet, wird jedes Mal count = count+1 im Cache festgelegt. Wenn der Benutzer die Seite zum ersten Mal besucht, wird der Zählwert in Redis auf 1 gesetzt. Jedes Mal, wenn der Benutzer die Seite in Zukunft besucht, wird der Zähler um 1 erhöht und schließlich auf Redis zurückgesetzt.

Auf diese Weise kann dort, wo die Menge angezeigt werden muss, der Zählwert von Redis ermittelt und zurückgegeben werden.

In diesem Szenario ist es nicht erforderlich, count(*)-Echtzeitstatistiken aus der Datenpunkttabelle zu verwenden, und die Leistung wird erheblich verbessert. In Situationen mit hoher Parallelität kann es jedoch zu Dateninkonsistenzen zwischen dem Cache und der Datenbank kommen. Für Geschäftsszenarien wie das Zählen der Gesamtzahl der Aufrufe oder der Gesamtzahl der Besucher ist die Genauigkeit der Daten jedoch nicht hoch und Dateninkonsistenzen werden toleriert.

2.2 Multithread-Ausführung

Es besteht beispielsweise ein Bedarf: Zählen Sie, wie viele gültige Bestellungen es gibt und wie viele ungültige Bestellungen es gibt.

In diesem Fall müssen im Allgemeinen zwei SQLs geschrieben werden. Die zum Zählen gültiger Bestellungen verwendeten SQLs sind wie folgt:

select count(*) from order where status=1;

Die SQL zum Zählen ungültiger Bestellungen lautet wie folgt:

select count(*) from order where status=0;

 Wenn es sich jedoch um eine Schnittstelle handelt, ist die Effizienz der synchronen Ausführung dieser beiden SQLs sehr gering. Zu diesem Zeitpunkt können Sie es in SQL ändern:

select count(*),status from order
group by status;

Durch die Verwendung group byder Schlüsselwortgruppierung zum Zählen der Anzahl mit demselben Status werden nur zwei Datensätze generiert, ein Datensatz ist die Anzahl gültiger Bestellungen und der andere Datensatz ist die Anzahl ungültiger Bestellungen. Es gibt jedoch ein Problem: Das Statusfeld hat nur zwei Werte 1 und 0. Der Wiederholungsgrad ist sehr hoch und der Differenzierungsgrad sehr gering. Es kann nicht indiziert werden und scannt die gesamte Tabelle nicht sehr effizient.

Gibt es noch andere Lösungen? Antwort: Verwenden Sie Multithreading.

CompleteFutureWir können zwei asynchrone Aufrufe von SQL verwenden 线程, um gültige Bestellungen zu zählen, und SQL, um ungültige Bestellungen zu zählen, und schließlich die Daten zusammenfassen, was die Leistung der Abfrageschnittstelle verbessern kann.

2.3 Join-Tabellen reduzieren

In den meisten Fällen wird count(*) verwendet, um die Gesamtmenge in Echtzeit zu zählen. Wenn jedoch die Datenmenge in der Tabelle selbst gering ist, aber zu viele Join-Tabellen vorhanden sind, kann dies auch die Effizienz von count(*) beeinträchtigen. Wenn Sie beispielsweise Produktinformationen abfragen, müssen Sie Daten basierend auf Produktname, Einheit, Marke, Klassifizierung und anderen Informationen abfragen. Schreiben Sie zu diesem Zeitpunkt eine SQL, um die gewünschten Daten zu finden, z. B. die folgenden:

select count(*)
from product p
inner join unit u on p.unit_id = u.id
inner join brand b on p.brand_id = b.id
inner join category c on p.category_id = c.id
where p.name='测试商品' and u.id=123 and b.id=124 and c.id=125;

Über die Produkttabelle gelangen Sie zu joinden drei Tabellen Einheit, Marke und Kategorie. Tatsächlich können diese Abfragebedingungen Daten in der Produkttabelle abfragen, und es ist nicht erforderlich, zusätzliche Tabellen zu verknüpfen.

Wir können die SQL wie folgt ändern:

select count(*)  
from product
where name='测试商品' and unit_id=123 and brand_id=124 and category_id=125;

Fragen Sie beim Zählen (*) nur die Produkttabelle ab und entfernen Sie die redundanten Tabellenverknüpfungen, sodass die Abfrageeffizienz erheblich verbessert werden kann.

Leistungsvergleich verschiedener Verwendungen von 3 count

  • count(*): Es werden die Daten aller Zeilen ohne Verarbeitung abgerufen und 1 zur Anzahl der Zeilen addiert.

  • count(1): Es werden die Daten aller Zeilen abgerufen, mit einem festen Wert von 1 für jede Zeile, was auch der Anzahl der Zeilen plus 1 entspricht.

  • count(id): id stellt den Primärschlüssel dar. Es muss das ID-Feld aus allen Datenzeilen analysiert werden. Die ID darf nicht NULL sein und die Anzahl der Zeilen wird um 1 erhöht.

  • count (normale Indexspalte): Es muss die gewöhnliche Indexspalte aus den Daten aller Zeilen analysieren und dann feststellen, ob sie NULL ist. Wenn sie nicht NULL ist, wird die Anzahl der Zeilen um 1 erhöht.

  • count (nicht indizierte Spalte): Durchsucht die gesamte Tabelle, um alle Daten zu erhalten, analysiert die nicht indizierte Spalte und bestimmt dann, ob sie NULL ist. Wenn sie nicht NULL ist, wird die Anzahl der Zeilen um 1 erhöht.

Daraus ergibt sich für die endgültige Zählleistung von hoch nach niedrig:

count(*) ≈ count(1) > count(id) > count (normale Indexspalte) > count (nicht indizierte Spalte) 

Es ist also count(*)tatsächlich das schnellste. 

おすすめ

転載: blog.csdn.net/qq_25285531/article/details/130981039