2012-09-18 8 views
28

Zählen Tabellen mit großen Datenmengen möglicherweise sehr langsam, manchmal dauert es Minuten; Es kann auch Deadlock auf einem ausgelasteten Server generieren. Ich möchte reale Werte anzeigen, NOLOCK ist keine Option.SQL Server Count ist langsam

Die Server, die ich verwende, sind SQL Server 2005 oder 2008 Standard oder Enterprise - wenn es darauf ankommt. Ich kann mir vorstellen, dass SQL Server die Zählungen für jede Tabelle verwaltet und wenn es keine WHERE-Klausel gibt, könnte ich diese Nummer ziemlich schnell bekommen, oder?

Zum Beispiel:

SELECT COUNT(*) FROM myTable 

sollte sofort mit dem richtigen Wert zurück. Muss ich mich darauf verlassen, dass Statistiken aktualisiert werden?

+2

einen [Abfrageausführungsplan] (http://stackoverflow.com/questions/7359702/how-do -i-erhalte-einen-Abfrage-Ausführungsplan, dann können wir reden ...('SELECT COUNT' fragt die Tabelle direkt ab, anstatt Statistiken zu verwenden, da Statistiken möglicherweise veraltet sind.) – Justin

+2

Dumme Frage, aber haben Sie einen Index? – Kermit

+0

@FreshPrinceOfSO es ist immer noch langsam, wenn Sie auf "Id" zählen (Bigint, Primärschlüssel, Identitätsspezifikation = wahr). – ANeves

Antwort

37

Ganz in der Nähe ungefähre (alle im Flug Transaktionen ignoriert wird) wäre:

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'myTable' 
    AND s.name = N'dbo' 
    AND p.index_id IN (0,1); 

Dieser Wille viel schneller zurückgeben als COUNT (*), und wenn sich Ihr Tisch schnell genug ändert, ist er nicht weniger genau - wenn Ihr Tisch zwischen dem Start von COUNT und der Rückgabe gewechselt hat, ist das viel wertvoller ?

+0

Kann auch verwendet werden, wenn kein Index vorhanden ist. – Kermit

+0

Ihre Lösung sah sehr vielversprechend aus, aber nachdem ich etwa 5 Millionen Datensätze getestet hatte, bekam ich die gleichen Antwortzeiten. wird bald auf einer größeren Datenbank testen. – Adi

+2

@Adi Eine Abfrage gegen sys.partitions dauerte lange? Ich finde das sehr schwer zu glauben. –

8

(Wie groß ist „große Menge an Daten?“ - dieser ersten kommentiert haben sollte, aber vielleicht unter der exec hilft Ihnen aus bereits)

Wenn ich eine Abfrage auf einem statischen laufen (bedeutet, dass niemand sonst nervig mit lesen/schreiben/updates in einer ganzen Weile, so dass die Konkurrenz kein Problem ist) Tabelle mit 200 Millionen Zeilen und COUNT (*) in 15 Sekunden auf meinem Dev-Rechner (oracle). die reine Datenmenge betrachtet, ist dies immer noch recht schnell (zumindest für mich)

Wie Sie gesagt haben NOLOCK keine Option ist, könnten Sie

exec sp_spaceused 'myTable' 

prüfen, wie gut.

Aber diese Stifte fast bis auf die gleiche wie NOLOCK (Behauptung ignoriert + löschen/update afaik)

2

Count führt entweder einen Tabellenscan oder einen Indexscan aus. Für eine hohe Anzahl von Zeilen wird es also langsam. Wenn Sie diese Operation häufig ausführen, besteht der beste Weg darin, den Zähldatensatz in einer anderen Tabelle zu belassen.

Wenn Sie aber nicht wollen, das zu tun, Sie einen Dummy-Index erstellen können (das wird nicht von der Abfrage verwendet werden) und Abfrage es ist Anzahl der Elemente, so etwas wie:

select 
    row_count 
from sys.dm_db_partition_stats as p 
inner join sys.indexes as i 
    on p.index_id = i.index_id 
    and p.object_id = i.object_id 
where i.name = 'your index' 

ich vorschlage Erstellen eines neuen Indexes, da dieser (wenn er nicht verwendet wird) während anderer Operationen nicht gesperrt wird.

Wie Aaron Bertrand sagte, könnte die Pflege der Abfrage teurer sein als die Verwendung eines bereits vorhandenen. Also die Wahl liegt bei dir.

+0

Aber selbst wenn dieser Index nicht für andere * read * -Operationen verwendet wird, muss er auch für andere DML beibehalten werden. Ich denke, dieser Dummy Index ist teurer als Sie denken. –

+0

Es könnte sein, wie Sie sagen. Es muss getestet werden. Die SQL kann verwendet werden, ohne dass tatsächlich ein neuer Index erstellt wird, sondern auf einem vorhandenen Index. Ich habe bei gefilterten Indizes etwas Ähnliches verwendet. Ich brauchte nie den Tisch von Kopf bis Fuß zu zählen. –

0

Wenn Sie nur eine ungefähre Anzahl von Zeilen benötigen, dh. um sicherzustellen, dass die Daten korrekt oder um sicherzustellen, dass eine Tabelle gelöscht wurden nicht geladen, gehen Sie wie folgt vor: Get

MySQL> connect information_schema; 
MySQL> select table_name,table_rows from tables;