SQL SERVER – SUM(1) vs COUNT(*) – Performance Observation

My Performance Observation found similar counting plans for a nonempty table. SUM(1) and COUNT(*) still differ on empty input.

Three tools inspect one populated source while a separate empty tray remains visible.

CREATE TABLE #TestTable (ID int NOT NULL, Padding char(100) NULL);
CREATE INDEX IX_TestTable_ID ON #TestTable(ID);
INSERT #TestTable(ID) VALUES (1),(2),(3);
SET STATISTICS IO ON;
SELECT COUNT(*) AS CountStar FROM #TestTable;
SELECT COUNT(1) AS CountOne FROM #TestTable;
SELECT SUM(1) AS SumOne FROM #TestTable;
SET STATISTICS IO OFF;
DELETE #TestTable;
SELECT COUNT(*) AS EmptyCount,SUM(1) AS EmptySum FROM #TestTable;
DROP TABLE #TestTable;
Original screen order: COUNT(*), COUNT(1) and SUM(1) each return 3 for the nonempty input; the empty input returns COUNT 0 and SUM NULL.
Original screen order: COUNT(*), COUNT(1) and SUM(1) each return 3 for the nonempty input; the empty input returns COUNT 0 and SUM NULL.
Historical plan comparison using the original TestTable and its narrow index.
Historical plan comparison using the original TestTable and its narrow index.
Historical STATISTICS IO comparison for that original workload.
Historical STATISTICS IO comparison for that original workload.

My earlier example used the same narrow index and logical reads for three shapes. That was a specific test. The temporary-table companion has its own size and plan. It does not reproduce the earlier timings.

On empty input, COUNT(*) returns zero and SUM(1) returns NULL. COUNT(1) counts every row. Datatype and overflow choices also matter for large inputs. Use COUNT_BIG when the count can exceed int.

I choose the expression that states the intended result. Then I compare actual plans and reads for representative data. Preserve correct behavior before optimizing performance.

Related reading

A matching test plan is not universal expression equivalence, it is an observation under specific data and conditions.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

Execution Plan, SQL Scripts, SQL Server
Previous Post
Index Used for COUNT(*): SQL Server Scans the Narrowest One
Next Post
Latch Waits at the Top: Reading sys.dm_os_latch_stats

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.