Compartilhar via


SQL Server Mythen: Die COUNT(*) Debatte

Zu den weitverbreiteten Mythen in Bezug auf SQL Server gehört die Behauptung, dass man zum Zeilen zählen aus Performancegründen lieber COUNT(1) statt COUNT(*) nehmen soll. Das ist nicht s. In beiden Fällen (und bei COUNT(2), COUNT(3),...)  ist der Ausführungsplan absolut identisch: SQL Server geht durch die Tabelle und zählt die Anzahl der Zeilen. Insbesondere ist COUNT(1) auch nicht identisch mit COUNT([erste Spalte]), denn beim Zählen der Werte einer Spalte werden nur die Zeilen berücksichtigt, in denen der Wert der Spalte nicht NULL ist.

Das kann man mit einem kleinen Beispiel leicht sehen:

use tempdb

create table #counttest (col1 int null, col2 int null)

go

insert into #counttest (col1, col2) values (null, 1)
insert into #counttest (col1, col2) values (1, null)
insert into #counttest (col1, col2) values (2, 2)
insert into #counttest (col1, col2) values (3, null)

select COUNT(*), COUNT(1), COUNT(2), COUNT(col1), COUNT(col2) from #counttest

Warte mal sagen jetzt vielleicht einige - SQL Server geht durch die gesamte Tabelle um die Zeilen zu zählen? Macht also einen Table Scan? Das kann doch lange dauern?!

Richtig, wie sonst soll SQL Server wissen, wie viele Zeilen wirklich in der Tabelle sind? Bei jeder Operation ein Metadatenfeld mit der Zeilenzahl zu pflegen wäre in einer hoch parallelen Implementation ein Bottleneck. Daher passiert das nicht.

Aber es gibt dennoch zwei Wege, um schnell die ungefähre Zeilenzahl zu ermitteln.

Über sys.partitions:

SELECT SUM([rows]) FROM sys.partitions

WHERE [object_id] = object_id('#counttest')

AND [index_id] IN (0,1);

oder wer DMVs bevorzugt über sys.dm_db_partition_stats

SELECT SUM([row_count]) FROM sys.dm_db_partition_stats

WHERE [object_id] = object_id('#counttest')

AND [index_id] IN (0,1);

In beiden Fällen ist das SUM nur notwendig, wenn die Tabelle partitioniert ist. Sonst gibt es nur eine Zeile mit Index_id 0 (Tabelle ist ein Heap) oder 1 (Tabelle ist ein Clustered Index).

Die Anzahl der Zeilen in diesen Views wird regelmäßig aktualisiert, kann aber von der tatsächlichen Zeilenzahl etwas abweichen. Wer's genau braucht muss COUNT(*) verwenden.

Gruß,
Steffen

Comments