Der schnellste Weg, um die genaue Anzahl der Zeilen in einer sehr großen Tabelle zu zählen?

234

Ich bin auf Artikel gestoßen, die besagen, dass SELECT COUNT(*) FROM TABLE_NAMEsie langsam sind, wenn die Tabelle viele Zeilen und viele Spalten enthält.

Ich habe eine Tabelle, die vielleicht sogar Milliarden von Zeilen enthält [sie hat ungefähr 15 Spalten]. Gibt es eine bessere Möglichkeit, die GENAUE Anzahl der Zeilen einer Tabelle zu ermitteln?

Bitte beachten Sie vor Ihrer Antwort Folgendes:

  • Ich suche eine datenbankunabhängige Lösung. Es ist in Ordnung, wenn es MySQL , Oracle , MS SQL Server abdeckt . Aber wenn es wirklich keine datenbankanbieterunabhängige Lösung gibt, werde ich mich mit unterschiedlichen Lösungen für unterschiedliche Datenbankanbieter zufrieden geben.

  • Ich kann dazu kein anderes externes Tool verwenden. Ich suche hauptsächlich eine SQL-basierte Lösung.

  • Ich kann mein Datenbankdesign nicht weiter normalisieren. Es ist bereits in 3NF und außerdem wurde bereits viel Code darum geschrieben.

Swaranga Sarma
quelle
4
Und nur neugierig, warum es die genaue augenblickliche Anzahl von Zeilen benötigt, wenn Sie Milliarden von ihnen haben ...
zerkms
2
Würden wir nicht alle hoffen, dass dieses spezielle Konstrukt von unserem Datenbankanbieter optimiert wurde?
KevinDTimm
5
@Swaranga, können Sie etwas näher erläutern, was dieser Zweck der Datenbankwartung ist, bei dem die genaue Anzahl der Zeilen in der Tabelle bekannt sein muss? Ich kann es mir nicht vorstellen. Und wie Kevin sagt, wenn es einen schnelleren Weg als COUNT (*) gäbe, würde (sollte) der DBMS-Anbieter COUNT (*) sicher erneut implementieren, um es zu verwenden ...
Tony Andrews
3
Wenn die Tabelle häufig geschrieben wird, ist Ihre genaue Anzahl sicherlich nur für einen bestimmten Zeitpunkt genau und möglicherweise nicht einmal genau, wenn andere Prozesse in die Tabelle schreiben, es sei denn, Sie setzen eine Tabellensperre für die Abfrage.
Steve Ford
2
Sie könnten Trigger zum Einfügen und Löschen verwenden, um eine fortlaufende Zählung durchzuführen?
Paparazzo

Antworten:

246

Einfache Antwort:

  • Datenbankanbieterunabhängige Lösung = Verwenden Sie den Standard = COUNT(*)
  • Es gibt ungefähre SQL Server-Lösungen, aber verwenden Sie COUNT (*) = nicht außerhalb des Gültigkeitsbereichs

Anmerkungen:

COUNT (1) = COUNT (*) = COUNT (PrimaryKey) für alle Fälle

Bearbeiten:

SQL Server-Beispiel (1,4 Milliarden Zeilen, 12 Spalten)

SELECT COUNT(*) FROM MyBigtable WITH (NOLOCK)
-- NOLOCK here is for me only to let me test for this answer: no more, no less

1 Läufe, 5:46 Minuten, Anzahl = 1.401.659.700

--Note, sp_spaceused uses this DMV
SELECT
   Total_Rows= SUM(st.row_count)
FROM
   sys.dm_db_partition_stats st
WHERE
    object_name(object_id) = 'MyBigtable' AND (index_id < 2)

2 Läufe, beide unter 1 Sekunde, zählen = 1.401.659.670

Der zweite hat weniger Zeilen = falsch. Wäre je nach Schreibvorgang gleich oder höher (Löschvorgänge werden hier außerhalb der Geschäftszeiten ausgeführt)

gbn
quelle
9
Nein , COUNT(*) = COUNT(key). Das ist einfach falsch. Wenn es keine NOT NULLEinschränkung gibt, können sie nicht gleich sein (sowohl in den Ergebnissen als auch im Ausführungsplan).
Zerkms
14
@zerkmsby: Für COUNT (Schlüssel) habe ich COUNT (Primärschlüssel) gemeint, der nicht nullwertfähig sein sollte. Ich werde klarstellen
gbn
8
Mit (NOLOCK) kann es nicht in der Produktion ausgeführt werden, und es kann zu einer ungenauen Zählung führen. Wenn Sie diesen Hinweis verwenden, stellen Sie sicher, dass Sperren verhindert werden. Die Nebenwirkungen einer Produktionsbox sind jedoch, dass Sie in bestimmten Situationen die Zeilen zweimal zählen oder in anderen Situationen die Zeilen überspringen können. NOLOCK ist besser für eine Tabelle zu verwenden, in die nicht geschrieben wird, da es "Dirty Reads" ermöglicht. Raten Sie den Leuten nicht, diesen Hinweis zu verwenden, es sei denn, sie verstehen die Konsequenzen vollständig
Davos
4
@mishrsud Die einzige genaue Abfrage ist SELECT COUNT (*), aber sie ist langsam. Sie können entweder genau und langsam oder rau und schnell haben. Was Sie tun, hängt davon ab, was für den Zweck, für den Sie die Zählung benötigen, wichtiger ist. NO LOCK kann Zeilen einschließen oder ausschließen, die sich während der Transaktion befinden oder Seiten verschieben, aus welchem ​​Grund auch immer.
Davos
5
@gbn sehr schöne Lösung, können Sie sagen, was verwendet wird index_id < 2?
Commit
29

Der mit Abstand schnellste Weg unter MySQL ist:

SHOW TABLE STATUS;

Sie erhalten sofort alle Ihre Tabellen mit der Zeilenanzahl (das ist die Summe) zusammen mit vielen zusätzlichen Informationen, wenn Sie möchten.

Salbahra
quelle
1
Intelligente Methode. Auf diese Weise können Sie die Zeilenanzahl mehrerer Tabellen in einer Abfrage abrufen.
Deval Khandelwal
Haben Sie auf db Tabellen mit ~ Milliarden Einträgen wie @gbn ausgeführt und die Zeit bemerkt?
KNU
Welcher Wert ist die Gesamtzahl der Zeilen für alle Tabellen in der Datenbank? Und diese sind ungefähr - was ist, wenn Sie genaue Werte für die Zeilenanzahl wünschen?
Kreeverp
2
Dies funktioniert überhaupt nicht, auf INNODB liest die Speicher-Engine beispielsweise einige Zeilen und extrapoliert sie, um die Anzahl der Zeilen zu erraten
Martijn Scheffer
10

Ich bin auf Artikel gestoßen, die besagen, dass SELECT COUNT (*) FROM TABLE_NAME langsam ist, wenn die Tabelle viele Zeilen und viele Spalten enthält.

Das hängt von der Datenbank ab. Einige Beschleunigungen zählen, indem beispielsweise verfolgt wird, ob Zeilen im Index aktiv oder tot sind, sodass ein Index-Scan nur die Anzahl der Zeilen extrahieren kann. Andere tun dies nicht und erfordern daher den Besuch der gesamten Tabelle und das Zählen der Live-Zeilen nacheinander. Beides wird für einen riesigen Tisch langsam sein.

Beachten Sie, dass Sie im Allgemeinen eine gute Schätzung mithilfe von Abfrageoptimierungstools, Tabellenstatistiken usw. extrahieren können. Im Fall von PostgreSQL können Sie beispielsweise die Ausgabe von analysieren explain count(*) from yourtableund eine einigermaßen gute Schätzung der Anzahl der Zeilen erhalten. Was mich zu Ihrer zweiten Frage bringt.

Ich habe eine Tabelle, die sogar Milliarden von Zeilen enthalten könnte [sie hat ungefähr 15 Spalten]. Gibt es eine bessere Möglichkeit, die genaue Anzahl der Zeilen einer Tabelle zu ermitteln?

Ernsthaft? :-) Du meinst wirklich die genaue Anzahl aus einer Tabelle mit Milliarden von Zeilen? Bist du dir wirklich sicher? :-)

Wenn Sie dies wirklich tun, können Sie mithilfe von Triggern eine Spur der Gesamtsumme verfolgen. Beachten Sie jedoch die Parallelität und Deadlocks, wenn Sie dies tun.

Denis de Bernardy
quelle
Ja Denis, die genaue Anzahl ist erforderlich. :(
Swaranga Sarma
5
Es ist ein Glück, dass Google-Manager vernünftiger sind als Ihr Chef ... Stellen Sie sich vor, wie langsam es wäre, wenn die genaue Anzahl der Suchergebnisse für jede Ihrer Abfragen zurückgegeben würde, anstatt sich an eine geschätzte Anzahl zu halten.
Denis de Bernardy
Zumindest fühlst du dich in mich hinein. Wie wäre es mit einer einzigen Oracle-Lösung? Das wird mein Problem in gewissem Maße reduzieren. Derzeit verwendet der Kunde Oracle. Wenn ich also eine Problemumgehung nur für Oracle finde, reicht dies [vorerst]. :)
Swaranga Sarma
6
"Ja Denis, die genaue Anzahl ist erforderlich .::" - Nun, ich kann nur spekulieren. Stellt der Datenbankwartungsprozess fest, dass in Tabelle A 42.123.876 Zeilen vorhanden sind, und erstellt dann 42.123.876 leere Zeilen in Tabelle B und durchläuft dann die Tabelle A und aktualisiere die Zeilen in Tabelle B ...? Oder ist es verrückter als das? ;-)
Tony Andrews
1
Transaktion 2 kann nicht beginnen, bevor Transaktion 1 festgeschrieben wurde. Ohne das Update "Zähltabelle" könnten viele Update-Transaktionen parallel ausgeführt werden. Bei der "Zähltabelle" muss jede Transaktion "ein Ticket erhalten", um ihre Zählung zu aktualisieren. Transaktionen stehen also am Ticketautomaten in der Warteschlange (der Planer entscheidet, wer als nächster eine Sperre für die Zähltabelle erhält).
Erwin Smout
10

Gibt es eine bessere Möglichkeit, die genaue Anzahl der Zeilen einer Tabelle zu ermitteln?

Um Ihre Frage einfach zu beantworten: Nein .

Wenn Sie dazu einen DBMS-unabhängigen Weg benötigen, ist der schnellste Weg immer:

SELECT COUNT(*) FROM TableName

Einige DBMS-Anbieter haben möglicherweise schnellere Möglichkeiten, die nur für ihre Systeme funktionieren. Einige dieser Optionen sind bereits in anderen Antworten enthalten.

COUNT(*) sollte ohnehin vom DBMS optimiert werden (zumindest von jedem PROD-würdigen DB), versuchen Sie also nicht, deren Optimierungen zu umgehen.

Nebenbei bemerkt:
Ich bin sicher, dass viele Ihrer anderen Abfragen aufgrund Ihrer Tabellengröße ebenfalls lange dauern. Alle Leistungsprobleme sollten wahrscheinlich behoben werden, indem Sie schnell über Ihr Schemadesign nachdenken. Mir ist klar, dass Sie gesagt haben, dass es keine Option zum Ändern ist, aber es könnte sich herausstellen, dass Abfragen von mehr als 10 Minuten auch keine Option sind. 3. NF ist nicht immer der beste Ansatz , wenn Sie Geschwindigkeit benötigen, und manchmal können Daten in mehreren Tabellen aufgeteilt werden , wenn die Datensätze nicht haben , um zusammen gelagert werden. Etwas zum Nachdenken...

Jesse Webb
quelle
10

Ich habe dieses Skript von einer anderen StackOverflow-Frage / Antwort erhalten:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'YourTableNameHere'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);

Mein Tisch hat 500 Millionen Datensätze und die oben genannten Ergebnisse werden in weniger als 1 ms zurückgegeben. Inzwischen,

SELECT COUNT(id) FROM MyTable

dauert volle 39 Minuten, 52 Sekunden!

Sie ergeben genau die gleiche Anzahl von Zeilen (in meinem Fall genau 519326012).

Ich weiß nicht, ob das immer der Fall wäre.

JakeJ
quelle
Können Sie einen Parameter hinzufügen, um die Anzahl der Zeilen mit dieser Abfrage zu ermitteln? Beispiel: Wählen Sie COUNT (1) FROM TABLENAME WHERE ColumnFiled = '1' mit Ihrer Abfrage?
VnDevil
Das ist die Anzahl - die Anzahl der Zeilen (Datensätze) ist in diesem Fall die "Anzahl". "500 Millionen Datensätze" war eine ungefähre Zahl, und "519326012" war die genaue Anzahl der Zeilen oder die Anzahl. Zeilen = Datensätze = Anzahl.
JakeJ
9

Sie können dies versuchen sp_spaceused (Transact-SQL)

Zeigt die Anzahl der Zeilen, den reservierten Speicherplatz und den Speicherplatz an, die von einer Tabelle, einer indizierten Ansicht oder einer Service Broker-Warteschlange in der aktuellen Datenbank verwendet werden, oder zeigt den reservierten und von der gesamten Datenbank verwendeten Speicherplatz an.

Marmeladen
quelle
Wird sp_spaceused mir keine ungefähre Anzahl geben?
Swaranga Sarma
1
Zu Ihrer
Information
6

Wenn die SQL Server-Edition 2005/2008 ist, können Sie DMVs verwenden, um die Zeilenanzahl in einer Tabelle zu berechnen:

-- Shows all user tables and row counts for the current database 
-- Remove is_ms_shipped = 0 check to include system objects 
-- i.index_id < 2 indicates clustered index (1) or hash table (0) 
SELECT o.name, 
 ddps.row_count 
FROM sys.indexes AS i 
 INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID 
 INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID 
 AND i.index_id = ddps.index_id 
WHERE i.index_id < 2 
 AND o.is_ms_shipped = 0 
ORDER BY o.NAME 

Für das SQL Server 2000-Datenbankmodul funktionieren sysindexes. Es wird jedoch dringend empfohlen, die Verwendung in zukünftigen Editionen von SQL Server zu vermeiden, da diese möglicherweise in naher Zukunft entfernt werden.

Beispielcode aus: So erhalten Sie schnell und schmerzlos Tabellenzeilenzählungen

Alireza Maddah
quelle
Dies ist ungefähr nicht genau : siehe meine Antwort bitte
gbn
Kennen Sie ein Beispiel, bei dem dies nicht korrekt ist? AFAIK, es hängt nicht von aktualisierten Statistiken ab.
Alireza Maddah
5

ich benutze

select /*+ parallel(a) */  count(1) from table_name a;
Mainsh S.
quelle
Wählen Sie / * + parallel (a) * / count (1) aus Tabellenname a
Mainsh S
5

Ich bin bei weitem nicht so kompetent wie andere, die geantwortet haben, aber ich hatte ein Problem mit einem Verfahren, mit dem ich eine zufällige Zeile aus einer Tabelle ausgewählt habe (nicht übermäßig relevant), aber ich musste die Anzahl der Zeilen in meiner Referenztabelle kennen um den Zufallsindex zu berechnen. Bei Verwendung der herkömmlichen Funktion Count (*) oder Count (1) wurden gelegentlich bis zu 2 Sekunden benötigt, damit meine Abfrage ausgeführt werden konnte. Also benutze ich stattdessen (für meine Tabelle mit dem Namen 'tbl_HighOrder'):

Declare @max int

Select @max = Row_Count
From sys.dm_db_partition_stats
Where Object_Name(Object_Id) = 'tbl_HighOrder'

Es funktioniert hervorragend und die Abfragezeiten in Management Studio sind Null.

John regnet
quelle
1
FWIW, Sie sollten angeben, welchen Datenbankanbieter Sie verwenden. Ich denke, die Aussage wäre je nach Anbieter etwas anders.
ToolmakerSteve
5

Nun, spät um 5 Jahre und unsicher, ob es hilft:

Ich habe versucht, die Nr. Zu zählen. von Zeilen in einer SQL Server-Tabelle mit MS SQL Server Management Studio und einem Überlauffehler, dann habe ich Folgendes verwendet:

Wählen Sie count_big (1) FROM [Datenbankname]. [Datenbank]. [FactSampleValue];

Das Ergebnis :

24296650578 Zeilen

Kaliyug-Antagonist
quelle
5

Ich habe diesen guten Artikel gefunden. SQL Server - HOW-TO: Ruft schnell die genaue Zeilenanzahl für die Tabelle ab, aus martijnh1der eine gute Zusammenfassung für jedes Szenario hervorgeht.

Ich muss dies erweitern, wo ich eine Zählung basierend auf einer bestimmten Bedingung bereitstellen muss, und wenn ich diesen Teil herausfinde, werde ich diese Antwort weiter aktualisieren.

In der Zwischenzeit hier die Details aus dem Artikel:

Methode 1:

Abfrage:

SELECT COUNT(*) FROM Transactions 

Bemerkungen:

Führt einen vollständigen Tabellenscan durch. Langsam auf großen Tischen.

Methode 2:

Abfrage:

SELECT CONVERT(bigint, rows) 
FROM sysindexes 
WHERE id = OBJECT_ID('Transactions') 
AND indid < 2 

Bemerkungen:

Schneller Weg zum Abrufen der Zeilenanzahl. Hängt von Statistiken ab und ist ungenau.

Führen Sie DBCC UPDATEUSAGE (Database) WITH COUNT_ROWS aus, was bei großen Tabellen viel Zeit in Anspruch nehmen kann.

Methode 3:

Abfrage:

SELECT CAST(p.rows AS float) 
FROM sys.tables AS tbl 
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and
idx.index_id < 2 
INNER JOIN sys.partitions AS p ON p.object_id=CAST(tbl.object_id AS int) 
AND p.index_id=idx.index_id 
WHERE ((tbl.name=N'Transactions' 
AND SCHEMA_NAME(tbl.schema_id)='dbo')) 

Bemerkungen:

Die Art und Weise, wie das SQL Management Studio Zeilen zählt (siehe Tabelleneigenschaften, Speicher, Zeilenanzahl). Sehr schnell, aber immer noch eine ungefähre Anzahl von Zeilen.

Methode 4:

Abfrage:

SELECT SUM (row_count) 
FROM sys.dm_db_partition_stats 
WHERE object_id=OBJECT_ID('Transactions')    
AND (index_id=0 or index_id=1); 

Bemerkungen:

Schneller (wenn auch nicht so schneller wie Methode 2) Betrieb und ebenso wichtig, zuverlässig.

Thierry
quelle
Vielen Dank! Wirklich nützlicher Tipp. Ich habe keine Berechtigung zum Anzeigen von Systemtabellen, daher bin Methode 4 nicht ich. Methode 3 ist jedoch gut genug.
Nicholas Humphrey
3

Ich glaube nicht, dass es eine allgemeine, immer schnellste Lösung gibt: Einige RDBMS / Versionen haben eine spezielle Optimierung SELECT COUNT(*), die schnellere Optionen verwendet, während andere einfach Tabellen scannen. Sie müssten für den zweiten Satz zu den Dokumentations- / Support-Sites gehen, für die wahrscheinlich eine spezifischere Abfrage geschrieben werden muss, normalerweise eine, die auf irgendeine Weise auf einen Index trifft.

BEARBEITEN:

Hier ist ein Gedanke, der je nach Schema und Verteilung der Daten funktionieren könnte: Haben Sie eine indizierte Spalte, die beispielsweise auf einen zunehmenden Wert, eine numerisch zunehmende ID oder sogar einen Zeitstempel oder ein Datum verweist? Unter der Annahme, dass keine Löschvorgänge stattfinden, sollte es dann möglich sein, die Anzahl bis zu einem aktuellen Wert (gestriges Datum, höchster ID-Wert an einem aktuellen Stichprobenpunkt) zu speichern und die Anzahl darüber hinaus hinzuzufügen, was sich sehr schnell im Index auflösen sollte . Natürlich sehr abhängig von Werten und Indizes, aber für so ziemlich jede Version eines DBMS anwendbar.

Mike Woodhouse
quelle
Ich würde sehr hoffen, dass jedes anständige DBMS einen Index für verwenden würde SELECT COUNT(*). Sogar MySQL macht es anscheinend ....
Sleske
vorausgesetzt, Löschungen passieren nicht - ernsthaft? ; p
ToolmakerSteve
3

Ich komme zu spät zu dieser Frage, aber hier ist, was Sie mit MySQL tun können (da ich MySQL verwende). Ich teile meine Beobachtungen hier:

1) SELECT COUNT(*) AS TOTAL_ROWS FROM <TABLE_NAME>

Ergebnis Zeilenanzahl
: 508534
Konsolenausgabe: Betroffene Zeilen: 0 Gefundene Zeilen: 1 Warnungen: 0 Dauer für 1 Abfrage: 0,125 Sek.
Es dauert eine Weile für eine Tabelle mit einer großen Anzahl von Zeilen, aber die Zeilenanzahl ist sehr genau.

2) SHOW TABLE STATUS or SHOW TABLE STATUS WHERE NAME="<TABLE_NAME>"

Ergebnis Zeilenanzahl
: 511235
Konsolenausgabe: Betroffene Zeilen: 0 Gefundene Zeilen: 1 Warnungen: 0 Dauer für 1 Abfrage: 0,250 Sek. Zusammenfassung: Die Zeilenanzahl ist nicht genau.

3) SELECT * FROM information_schema.tables WHERE table_schema = DATABASE();

Ergebnis Zeilenanzahl
: 507806
Konsolenausgabe: Betroffene Zeilen: 0 Gefundene Zeilen: 48 Warnungen: 0 Dauer für 1 Abfrage: 1.701 Sek.
Die Zeilenanzahl ist nicht genau.

Ich bin kein MySQL- oder Datenbankexperte, aber ich habe festgestellt, dass Sie für sehr große Tabellen Option 2 oder 3 verwenden können, um eine „faire Vorstellung“ davon zu erhalten, wie viele Zeilen vorhanden sind.

Ich musste diese Zeilenzahlen abrufen, um einige Statistiken auf der Benutzeroberfläche anzuzeigen. Bei den oben genannten Abfragen wusste ich, dass die Gesamtzahl der Zeilen mehr als 500.000 betrug. Daher habe ich Statistiken wie "Mehr als 500.000 Zeilen" angezeigt, ohne die genaue Anzahl der Zeilen anzuzeigen.

Vielleicht habe ich die Frage des OP nicht wirklich beantwortet, aber ich teile mit, was ich in einer Situation getan habe, in der solche Statistiken benötigt wurden. In meinem Fall war es akzeptabel, die ungefähren Zeilen anzuzeigen, und so funktionierte das Obige für mich.

sunitkatkar
quelle
2

Nicht gerade eine DBMS-unabhängige Lösung, aber zumindest Ihr Client-Code wird den Unterschied nicht erkennen ...

Erstellen Sie eine weitere Tabelle T mit nur einer Zeile und einem Ganzzahlfeld N 1 und erstellen Sie INSERT TRIGGER, das gerade ausgeführt wird:

UPDATE T SET N = N + 1

Erstellen Sie auch einen DELETE TRIGGER, der Folgendes ausführt:

UPDATE T SET N = N - 1

Ein DBMS, das sein Salz wert ist, garantiert die Atomizität der Operationen über 2 , und N enthält zu jeder Zeit die genaue Anzahl der Zeilen, was dann sehr schnell zu erreichen ist:

SELECT N FROM T

Während Trigger DBMS-spezifisch sind, ist die Auswahl von T nicht und Ihr Client-Code muss nicht für jedes unterstützte DBMS geändert werden.

Dies kann jedoch zu Skalierbarkeitsproblemen führen, wenn die Tabelle INSERT- oder DELETE-intensiv ist, insbesondere wenn Sie COMMIT nicht unmittelbar nach INSERT / DELETE ausführen.


1 Diese Namen sind nur Platzhalter - verwenden Sie etwas Bedeutenderes in der Produktion.

2 Dh N kann nicht durch eine gleichzeitige Transaktion zwischen Lesen und Schreiben in N geändert werden, solange sowohl Lesen als auch Schreiben in einer einzigen SQL-Anweisung erfolgen.

Branko Dimitrijevic
quelle
2

Eine buchstäblich verrückte Antwort, aber wenn Sie eine Art Replikationssystem eingerichtet haben (für ein System mit einer Milliarde Zeilen hoffe ich), können Sie einen groben Schätzer (wie MAX(pk)) verwenden und diesen Wert durch die Anzahl der Slaves teilen Sie haben mehrere Abfragen parallel ausgeführt.

Zum größten Teil würden Sie die Abfragen auf der Grundlage des besten Schlüssels (oder des Primärschlüssels, denke ich) auf mehrere Slaves verteilen (wir werden 250000000 als unsere Zeilen / Slaves verwenden):

-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000

Sie benötigen jedoch nur SQL. Was für eine Büste. Ok, nehmen wir an, Sie sind ein Sadomasochist. Auf dem Master (oder dem nächsten Slave) müssten Sie höchstwahrscheinlich eine Tabelle dafür erstellen:

CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)

Anstatt nur die Auswahl in Ihren Slaves auszuführen, müssten Sie eine Einfügung durchführen, ähnlich wie folgt:

INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)

Möglicherweise treten Probleme mit Slaves auf, die auf dem Master in eine Tabelle schreiben. Möglicherweise müssen Sie noch mehr Sadis bekommen - ich meine, kreativ:

-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)

Sie sollten am Ende einen Slave haben, der zuletzt im Pfad vorhanden ist, der vom Replikationsdiagramm relativ zum ersten Slave durchlaufen wird. Dieser Slave sollte jetzt alle anderen Zählerwerte haben und seine eigenen Werte haben. Aber wenn Sie fertig sind, werden wahrscheinlich Zeilen hinzugefügt, sodass Sie eine weitere einfügen müssen, um das aufgezeichnete maximale pk in Ihrer counter_table und das aktuelle maximale pk zu kompensieren.

Zu diesem Zeitpunkt müssten Sie eine Aggregatfunktion ausführen, um die Gesamtzahl der Zeilen zu ermitteln. Dies ist jedoch einfacher, da Sie sie höchstens auf der Zeile "Anzahl der Slaves, die Sie haben und ändern" ausführen würden.

Wenn Sie in der Situation sind, dass Sie separate Tabellen in den Slaves haben, können UNIONSie alle Zeilen abrufen, die Sie benötigen.

SELECT SUM(cnt) FROM (
    SELECT * FROM counter_table_slave_1
      UNION
    SELECT * FROM counter_table_slave_2
      UNION
    ...
  )

Oder Sie wissen, seien Sie ein bisschen weniger verrückt und migrieren Sie Ihre Daten auf ein verteiltes Verarbeitungssystem oder verwenden Sie eine Data Warehousing-Lösung (die Ihnen auch in Zukunft eine beeindruckende Datenverarbeitung ermöglicht).

Beachten Sie, dass dies davon abhängt, wie gut Ihre Replikation eingerichtet ist. Da der primäre Engpass höchstwahrscheinlich ein dauerhafter Speicher ist, werden Sie wahrscheinlich langsamer als nur auf einen einzigen warten, wenn Sie über einen groben Speicher oder schlecht getrennte Datenspeicher mit starkem Nachbarrauschen verfügenSELECT COUNT(*) ...

Wenn Sie jedoch eine gute Replikation haben, sollten Ihre Geschwindigkeitsgewinne in direktem Zusammenhang mit der Anzahl oder den Slaves stehen. Wenn die alleinige Ausführung der Zählabfrage 10 Minuten dauert und Sie 8 Slaves haben, können Sie Ihre Zeit auf weniger als ein paar Minuten verkürzen. Vielleicht eine Stunde, um die Details dieser Lösung auszubügeln.

Natürlich würden Sie nie wirklich eine erstaunlich genaue Antwort erhalten, da diese verteilte Lösung einige Zeit in Anspruch nimmt, in der Zeilen gelöscht und eingefügt werden können, aber Sie können versuchen, eine verteilte Sperre von Zeilen in derselben Instanz zu erhalten und eine genaue Anzahl zu erhalten der Zeilen in der Tabelle für einen bestimmten Zeitpunkt.

Tatsächlich scheint dies unmöglich zu sein, da Sie im Grunde genommen an einer reinen SQL-Lösung festhalten und ich glaube nicht, dass Ihnen ein Mechanismus zur Verfügung gestellt wird, mit dem eine gesplittete und gesperrte Abfrage sofort über mehrere Slaves ausgeführt werden kann. Vielleicht, wenn Sie die Kontrolle über die Replikationsprotokolldatei hätten ... was bedeutet, dass Sie buchstäblich Slaves für diesen Zweck hochfahren würden, was zweifellos langsamer ist, als die Zählabfrage ohnehin nur auf einem einzelnen Computer auszuführen.

Da sind also meine zwei Pennys 2013.

Yangmun Choi
quelle
2

Wenn die Verwendung des Einfügetriggers zu teuer ist, aber ein Löschtrigger bereitgestellt werden kann und eine automatische Inkrementierung erfolgtid , wird die gesamte Tabelle einmal gezählt und die Zählung als last-countund gespeichert last-counted-id.

dann muss jeder Tag nur für id> zählen last-counted-id, das hinzufügen last-countund das neue speichern last-counted-id.

Der Löschauslöser würde die letzte Zählung verringern, wenn die ID des gelöschten Datensatzes <= die letzte gezählte ID ist.

ToolmakerSteve
quelle
.. Entschuldigung, ich habe keine Zeit, um das SQL anzuzeigen, das verwendet werden würde (mein SQL ist verrostet). Wenn jemand meine Antwort bearbeiten möchte, um SQL hinzuzufügen, wäre das großartig!
ToolmakerSteve
1

Wenn Sie eine typische Tabellenstruktur mit einer automatisch inkrementierenden Primärschlüsselspalte haben, in der Zeilen niemals gelöscht werden, ist das Folgende der schnellste Weg, um die Anzahl der Datensätze zu bestimmen, und sollte in den meisten ANSI-kompatiblen Datenbanken ähnlich funktionieren:

SELECT TOP(1) <primarykeyfield> FROM <table> ORDER BY <primarykeyfield> DESC;

Ich arbeite mit MS SQL-Tabellen, die Milliarden von Zeilen enthalten, die Antwortzeiten von weniger als einer Sekunde für Daten erfordern, einschließlich der Anzahl der Datensätze. Ein ähnlicher SELECT COUNT (*) würde im Vergleich Minuten dauern.

KevinS
quelle
1
Nicht ganz richtig - was ist, wenn eine INSERTTransaktion zurückgesetzt wird? Dieser Primärschlüsselwert würde fehlen, sodass die tatsächliche Anzahl der Datensätze um eins unter dem Maximalwert liegt.
Sir Crispalot
Das könnten Lücken in der Reihenfolge sein. Normalerweise ein Ergebnis von Rollbacks.
Osa E
Tatsächlich gibt es eine Änderung dieser Antwort, die möglicherweise erheblich schneller ist als count(*)wenn ein Datenbankanbieter nicht ausreichend optimiert hat count(*): Verfolgen Sie jeden Tag den letzten automatischen Index und die entsprechende Anzahl und fordern Sie eine Anzahl der darüber hinausgehenden Datensätze an. Kann auch mit deletes umgehen, wenn beim Löschen ein Trigger hinzugefügt wird, der die vorherige Summe verringert , wenn die gelöschte Datensatz-ID <= der letzte automatische Index ist.
ToolmakerSteve
1

Versuchen Sie dies für SQL Server

SELECT T.name, 
       I.rows AS [ROWCOUNT] 
FROM   sys.tables AS T 
       INNER JOIN sys.sysindexes AS I 
               ON T.object_id = I.id AND I.indid < 2 
WHERE T.name = 'Your_Table_Name'
ORDER  BY I.rows DESC 
Abhishek B Patel
quelle
0

Wählen Sie Zeilen aus sysindexes aus, wobei id = Object_ID ('TableName') und indid <2

Enzero
quelle
0

Setzen Sie einen Index auf eine Spalte. Dies sollte es dem Optimierer ermöglichen, einen vollständigen Scan der Indexblöcke anstelle eines vollständigen Scans der Tabelle durchzuführen. Dadurch werden Ihre E / A-Kosten erheblich gesenkt. Schauen Sie sich vorher und nachher den Ausführungsplan an. Messen Sie dann die Wanduhrzeit in beide Richtungen.

EvilTeach
quelle
Wenn eine Tabelle Milliarden von Zeilen ohne Index für eine Spalte enthält, treten weit verbreitete Leistungsprobleme auf, die weit über die in der ursprünglichen Frage angegebene Notwendigkeit hinausgehen. Gut, dass Sie dies erwähnen (nichts annehmen!) :)
ToolmakerSteve
0

Wenn Sie Oracle verwenden, wie wäre es damit (vorausgesetzt, die Tabellenstatistiken werden aktualisiert):

select <TABLE_NAME>, num_rows, last_analyzed from user_tables

last_analyzed zeigt die Zeit an, zu der die Statistiken zuletzt gesammelt wurden.

Diogo Ferreira
quelle
0

Mit PostgreSQL:

SELECT reltuples AS approximate_row_count FROM pg_class WHERE relname = 'table_name'
Dorian
quelle
-1

In SQL Server 2016 kann ich einfach die Tabelleneigenschaften überprüfen und dann die Registerkarte "Speicher" auswählen. Dies gibt mir die Zeilenanzahl, den von der Tabelle verwendeten Speicherplatz, den verwendeten Indexbereich usw. an.

SenSei
quelle
Er suchte nach einem database vendor independent solution. Auch dies erfordert eine GUI und kann nicht automatisiert werden. Auch ist es nicht schneller als COUNT (*)
Frieder
-3

Vielleicht etwas spät, aber dies könnte anderen für MSSQL helfen

; WITH RecordCount AS (SELECT ROW_NUMBER () OVER (ORDER BY COLUMN_NAME) AS [RowNumber] FROM TABLE_NAME) SELECT MAX (RowNumber) FROM RecordCount

Justus Swanevelder
quelle
Dies ist deutlich SCHLECHTER als COUNT (), es sei denn, wir haben SEHR Glück und der Optimierer schafft es, es auf COUNT () zu optimieren - warum sollte er in einer zufälligen Spalte SORTIEREN?!?
DSZ