Ich weiß, dass es im Allgemeinen eine schlechte Idee ist, solche Abfragen durchzuführen:
SELECT * FROM `group_relations`
Aber wenn ich nur die Anzahl haben möchte, sollte ich mich für diese Abfrage entscheiden, da sich dadurch die Tabelle ändern kann, aber immer noch die gleichen Ergebnisse erzielt werden.
SELECT COUNT(*) FROM `group_relations`
Oder umso spezifischer
SELECT COUNT(`group_id`) FROM `group_relations`
Ich habe das Gefühl, dass Letzteres möglicherweise schneller sein könnte, aber gibt es noch andere Dinge zu beachten?
Update : In diesem Fall verwende ich InnoDB. Es tut mir leid, dass ich nicht genauer bin.
mysql
performance
innodb
grapefrukt
quelle
quelle
Antworten:
Wenn die betreffende Spalte NICHT NULL ist, sind beide Abfragen gleichwertig. Wenn group_id Nullwerte enthält,
select count(*)
zählt alle Zeilen, während
select count(group_id)
zählt nur die Zeilen, in denen group_id nicht null ist.
Einige Datenbanksysteme wie MySQL verwenden auch eine Optimierung, wenn Sie nach count (*) fragen, wodurch solche Abfragen etwas schneller als die spezifischen sind.
Persönlich, wenn ich nur zähle, zähle ich (*), um mit den Nullen auf der sicheren Seite zu sein.
quelle
group_id
) FROMgroup_relations
WHERE ROWNUM = 1Wenn ich mich richtig erinnere, zählt in MYSQL COUNT (*) alle Zeilen, während COUNT (Spaltenname) nur die Zeilen zählt, die in der angegebenen Spalte einen Wert ungleich NULL haben.
quelle
COUNT (*) zählt alle Zeilen, während COUNT (Spaltenname) nur Zeilen ohne NULL-Werte in der angegebenen Spalte zählt.
Wichtig in MySQL zu beachten:
COUNT () ist in MyISAM-Tabellen für * oder Nicht-Null-Spalten sehr schnell, da die Zeilenanzahl zwischengespeichert wird. InnoDB verfügt über kein Caching der Zeilenanzahl, daher gibt es keinen Leistungsunterschied für COUNT (*) oder COUNT (Spaltenname), unabhängig davon, ob die Spalte null sein kann oder nicht. Weitere Informationen zu den Unterschieden in diesem Beitrag finden Sie im MySQL-Performance-Blog.
quelle
Wenn Sie
SELECT COUNT(1) FROM
group_relations ausprobieren , ist dies etwas schneller, da nicht versucht wird, Informationen aus Ihren Spalten abzurufen.Bearbeiten: Ich habe gerade einige Nachforschungen angestellt und herausgefunden, dass dies nur in einigen Datenbanken geschieht. In sqlserver ist es dasselbe, 1 oder * zu verwenden, aber in Oracle ist es schneller, 1 zu verwenden.
http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/9367c580-087a-4fc1-bf88-91a51a4ee018/
Anscheinend gibt es keinen Unterschied zwischen ihnen in MySQL, wie bei SQL Server scheint der Parser die Abfrage zu ändern, um (1) auszuwählen. Entschuldigung, wenn ich Sie irgendwie irreführe.
quelle
Ich war selbst neugierig darauf. Es ist in Ordnung, Dokumentation und theoretische Antworten zu lesen, aber ich mag es, diese mit empirischen Beweisen in Einklang zu bringen.
Ich habe eine MySQL-Tabelle (InnoDB) mit 5.607.997 Datensätzen. Die Tabelle befindet sich in meiner eigenen privaten Sandbox, daher weiß ich, dass der Inhalt statisch ist und niemand den Server verwendet. Ich denke, dies beseitigt effektiv alle äußeren Auswirkungen auf die Leistung. Ich habe eine Tabelle mit einem Auto_increment-Primärschlüsselfeld (ID), von dem ich weiß, dass es niemals null sein wird, das ich für meinen where-Klauseltest verwenden werde (WHERE-ID IST NICHT NULL).
Der einzige andere mögliche Fehler, den ich beim Ausführen von Tests sehe, ist der Cache. Das erste Mal, wenn eine Abfrage ausgeführt wird, ist immer langsamer als nachfolgende Abfragen, die dieselben Indizes verwenden. Ich werde das unten als Cache-Seeding-Aufruf bezeichnen. Um es ein wenig zu verwechseln, habe ich es mit einer where-Klausel ausgeführt, von der ich weiß, dass sie unabhängig von Daten immer als wahr ausgewertet wird (TRUE = TRUE).
Das heißt hier sind meine Ergebnisse:
Abfragetyp
ANZAHL()
COUNT (Id)
COUNT (1)
++ Dies wird als Cache-Seeding-Aufruf betrachtet. Es wird erwartet, dass es langsamer als der Rest ist.
Ich würde sagen, die Ergebnisse sprechen für sich. COUNT (Id) verdrängt normalerweise die anderen. Das Hinzufügen einer Where-Klausel verkürzt die Zugriffszeit erheblich, selbst wenn es sich um eine Klausel handelt, von der Sie wissen, dass sie als wahr ausgewertet wird. Der Sweet Spot scheint COUNT (Id) zu sein ... WO Id NICHT NULL ist.
Ich würde gerne die Ergebnisse anderer Leute sehen, vielleicht mit kleineren Tabellen oder mit where-Klauseln gegen andere Felder als das Feld, das Sie zählen. Ich bin sicher, dass es andere Variationen gibt, die ich nicht berücksichtigt habe.
quelle
Suchen Sie nach Alternativen
Wie Sie gesehen haben, werden
COUNT
Abfragen langsam , wenn Tabellen groß werden. Ich denke, das Wichtigste ist, die Art des Problems zu berücksichtigen, das Sie lösen möchten. Beispielsweise verwenden viele EntwicklerCOUNT
Abfragen, wenn sie eine Paginierung für große Sätze von Datensätzen generieren, um die Gesamtzahl der Seiten in der Ergebnismenge zu bestimmen.Da
COUNT
Sie wissen, dass Abfragen langsam werden, können Sie eine alternative Methode zum Anzeigen von Paginierungssteuerelementen in Betracht ziehen, mit der Sie die langsame Abfrage einfach umgehen können. Die Paginierung von Google ist ein hervorragendes Beispiel.Denormalisieren
Wenn Sie unbedingt die Anzahl der Datensätze kennen müssen, die einer bestimmten Anzahl entsprechen, sollten Sie die klassische Technik der Daten-Denormalisierung in Betracht ziehen. Anstatt die Anzahl der Zeilen zum Zeitpunkt der Suche zu zählen, sollten Sie einen Zähler beim Einfügen eines Datensatzes erhöhen und diesen Zähler beim Löschen des Datensatzes verringern.
Wenn Sie sich dazu entschließen, sollten Sie idempotente Transaktionsoperationen verwenden, um diese denormalisierten Werte synchron zu halten.
BEGIN TRANSACTION; INSERT INTO `group_relations` (`group_id`) VALUES (1); UPDATE `group_relations_count` SET `count` = `count` + 1; COMMIT;
Alternativ können Sie Datenbank-Trigger verwenden, wenn Ihr RDBMS diese unterstützt.
Abhängig von Ihrer Architektur kann es sinnvoll sein, eine Caching-Ebene wie memcached zum Speichern, Inkrementieren und Dekrementieren des denormalisierten Werts zu verwenden und einfach zur langsamen COUNT-Abfrage zu wechseln, wenn der Cache-Schlüssel fehlt. Dies kann den allgemeinen Schreibkonflikt verringern, wenn Sie über sehr flüchtige Daten verfügen. In solchen Fällen sollten Sie jedoch Lösungen für den Dog-Pile-Effekt in Betracht ziehen .
quelle
MySQL ISAM-Tabellen sollten für COUNT (*) optimiert sein und den vollständigen Tabellenscan überspringen.
quelle
Ein Sternchen in COUNT hat keine Bedeutung mit einem Sternchen für die Auswahl aller Tabellenfelder. Es ist Unsinn zu sagen, dass COUNT (*) langsamer ist als COUNT (Feld)
Ich denke, dass die Auswahl von COUNT (*) schneller ist als die Auswahl von COUNT (Feld). Wenn das RDBMS feststellt, dass Sie "*" in COUNT anstelle des Felds angeben, muss es nichts auswerten, um die Anzahl zu erhöhen. Wenn Sie dagegen ein Feld in COUNT angeben, bewertet das RDBMS immer, ob Ihr Feld null ist oder nicht, um es zu zählen.
Wenn Ihr Feld jedoch nullwertfähig ist, geben Sie das Feld in COUNT an.
quelle
COUNT (*) Fakten und Mythen:
MYTHOS : "InnoDB verarbeitet Count (*) -Anfragen nicht gut":
Die meisten Zählabfragen (*) werden von allen Speicher-Engines auf dieselbe Weise ausgeführt, wenn Sie eine WHERE-Klausel haben. Andernfalls muss InnoDB einen vollständigen Tabellenscan durchführen.
FAKT : InnoDB optimiert keine Anzahl (*) Abfragen ohne die where-Klausel
quelle
Es ist am besten, nach einer indizierten Spalte wie einem Primärschlüssel zu zählen.
SELECT COUNT(`group_id`) FROM `group_relations`
quelle
Es sollte davon abhängen, was Sie tatsächlich erreichen wollen, wie Sebastian bereits gesagt hat, dh Ihre Absichten klarstellen! Wenn Sie sind nur die Zeilen zu zählen geht dann für die COUNT (*), oder eine einzelne Spalte geht für den COUNT (Spalte) zu zählen.
Möglicherweise lohnt es sich auch, Ihren DB-Anbieter zu überprüfen. Als ich Informix verwendete, hatte es eine Optimierung für COUNT (*), die Ausführungskosten für einen Abfrageplan von 1 hatte, verglichen mit dem Zählen einzelner oder mehrerer Spalten, was zu einer höheren Zahl führen würde
quelle
COUNT (1) war früher schneller als COUNT (*), aber das stimmt nicht mehr, da moderne DBMS klug genug sind, um zu wissen, dass Sie nichts über Spalten wissen möchten
quelle
Der Rat, den ich von MySQL zu solchen Dingen erhalten habe, ist, dass der Versuch, eine Abfrage basierend auf solchen Tricks zu optimieren, auf lange Sicht ein Fluch sein kann. Es gibt Beispiele in der Geschichte von MySQL, in denen die Hochleistungstechnik von jemandem, die sich auf die Funktionsweise des Optimierers stützt, in der nächsten Version zum Engpass wird.
Schreiben Sie die Abfrage, die die von Ihnen gestellte Frage beantwortet. Wenn Sie alle Zeilen zählen möchten, verwenden Sie COUNT (*). Wenn Sie eine Anzahl von Nicht-Null-Spalten wünschen, verwenden Sie COUNT (col) WHERE col IS NOT NULL. Indizieren Sie entsprechend und überlassen Sie die Optimierung dem Optimierer. Der Versuch, eigene Optimierungen auf Abfrageebene vorzunehmen, kann manchmal dazu führen, dass das integrierte Optimierungsprogramm weniger effektiv ist.
Das heißt, es gibt Dinge, die Sie in einer Abfrage tun können, um es dem Optimierer zu erleichtern, sie zu beschleunigen, aber ich glaube nicht, dass COUNT eine davon ist.
Bearbeiten: Die Statistiken in der obigen Antwort sind jedoch interessant. Ich bin mir nicht sicher, ob in diesem Fall tatsächlich etwas im Optimierer am Werk ist. Ich spreche nur von Optimierungen auf Abfrageebene im Allgemeinen.
quelle
Wie Ihre Frage impliziert, ist der Grund
SELECT *
schlecht beraten, dass Änderungen an der Tabelle Änderungen in Ihrem Code erfordern könnten. Das gilt nicht fürCOUNT(*)
. Es ist ziemlich selten, dass Sie das spezielle Verhalten wünschen,SELECT COUNT('group_id')
das Sie erhalten - normalerweise möchten Sie die Anzahl der Datensätze wissen. DafürCOUNT(*)
ist es da, also benutze es.quelle