Count(*) vs Count(1) - SQL Server
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In SQL Server, COUNT(*) and COUNT(1) are functionally equivalent for counting rows. The long-running debate about one being faster than the other is mostly folklore. In practice, the more useful comparison is usually COUNT(*) versus COUNT(column).
What COUNT(*) Means
COUNT(*) counts rows returned by the query:
It does not care which columns are null because it is counting rows, not values from a particular column.
This is also true with filters and joins. COUNT(*) simply counts the rows in the result set after the FROM, JOIN, and WHERE logic is applied.
What COUNT(1) Means
COUNT(1) counts a constant non-null expression for each row:
Because the expression 1 is non-null for every row, the result is the same as COUNT(*).
In SQL Server, the optimizer understands this. For ordinary row-counting queries, COUNT(*) and COUNT(1) produce the same result and are typically optimized the same way.
Where People Get Confused
The real difference is not between COUNT(*) and COUNT(1). It is between those forms and COUNT(column):
This counts only the rows where ManagerId is not null. That is a different question.
Example:
Expected result:
- '
COUNT(*)= 3' - '
COUNT(1)= 3' - '
COUNT(Value)= 2'
That difference matters much more than the * versus 1 style debate.
Which Form Should You Write
In SQL Server code, COUNT(*) is usually the clearest choice when you mean “count rows.” It states your intention directly and is the most widely recognized convention.
There is no practical advantage to rewriting that as COUNT(1).
Counting in Joins and Groups
The same guidance applies in grouped queries:
That counts rows per department. If you instead write COUNT(EmailAddress), then departments with null email values will be counted differently.
So when reviewing grouped SQL, ask “am I counting rows or non-null values from this column?” That is the decision that matters.
Performance Myths
You will sometimes hear claims that COUNT(1) is faster because SQL Server does not need to expand *. In modern SQL Server, that is not how the query should be understood. The optimizer does not literally iterate over every column because of the asterisk.
For normal row counts, both forms are optimized to the same plan shape in ordinary scenarios. If a query is slow, the cause is far more likely to be:
- table size
- predicates
- indexing
- join shape
- blocking or concurrency
Switching COUNT(*) to COUNT(1) is not the fix.
A Related Tool: COUNT_BIG
If you may exceed the integer range of COUNT, SQL Server also offers COUNT_BIG:
This is not about speed either. It is about the size of the return type.
Common Pitfalls
The most common mistake is assuming COUNT(column) behaves like COUNT(*). It does not. Nulls are excluded.
Another pitfall is spending time micro-optimizing COUNT(*) versus COUNT(1) while ignoring much larger query design issues.
Developers also sometimes choose COUNT(1) because they think it signals better performance. In SQL Server, it mostly signals style preference.
Finally, when joins duplicate rows, COUNT(*) counts those duplicate joined rows. If you really need distinct entities, use COUNT(DISTINCT ...) where supported by the query design.
Summary
- In SQL Server,
COUNT(*)andCOUNT(1)are effectively equivalent for row counting. - '
COUNT(*)is usually the clearest and most conventional form.' - '
COUNT(column)is different because it ignores null values in that column.' - Performance differences between
COUNT(*)andCOUNT(1)are generally not meaningful in practice. - Focus on query intent and execution plan quality, not folklore about the asterisk.

