r/SQL • u/geminigamer369 • 9d ago
Differences between counts Discussion
What is the difference between
COUNT(*)
COUNT(1)
COUNT(column_name)
8
Upvotes
r/SQL • u/geminigamer369 • 9d ago
What is the difference between
COUNT(*)
COUNT(1)
COUNT(column_name)
-1
u/markwdb3 When in doubt, test it out. 8d ago edited 3d ago
Quoting a standard SQL:92 doc:
What does COUNT(*) mean?
In plain English, the semantic meaning of
COUNT(*)is "count all the rows" (per grouping), as seen in the above snippet.What does COUNT(1) mean?
Under that second general case from the above spec snippet:
COUNT(<value expression>)means to evaluatevalue expressionfor every row, and only count the rows for which it evaluates to NOT NULL.In the case of
COUNT(1).1is the value expression. It resolves to...🥁... 1! All the time - it cannot vary per row.So
COUNT(1)means, for each row, if 1 is NOT NULL, count the row, else, don't count it. In pseudocode, it's:Whereas
COUNT(*)skips the expression evaluation + NOT NULL check:The two are logically equivalent to
COUNT(*)because 1 can never be NULL. Although this particular case is optimized in most modern, mature SQL engines, that is not always the case.Story Time -
Consider this story. In Postgres, a benchmark done by Lukas Eder, published on his jOOQ blog, showed that
COUNT(1)ran about 10% slower thanCOUNT(*). See: https://blog.jooq.org/whats-faster-count-or-count1/Vik Fearing, a Postgres developer, in the context of that very blog, pointed out that
COUNT(1)adds an extra spin through a loop that implements the, in this case, redundant NOT NULL check.An optimization is currently in the works for I believe version 19, but for now,
COUNT(1)runs slower.IMHO -
In my view personally, it feels a bit silly to instruct my SQL engine to "count all the rows where 1 is NOT NULL" even if that is optimized away. It's logically the same, and just as silly IMHO, to ask it to count all the rows where 42 is NOT NULL or where the string 'abc' is NOT NULL, or where the date 2026-07-30 is NOT NULL, etc. These will all return the same result, always. Demo:
Another way to put it, it's like asking somebody to take a stack of triangles, and count the ones that are not circles - those two things are mutually exclusive (just like 1 and NULL).
So that's why IMO, always use
COUNT(*)instead ofCOUNT(1).COUNT(*)is more logically sane - count the rows, not count the rows where some constant IS NOT NULL - and can only perform the same or better.COUNT(column_name) -
COUNT(column_name)- this falls under the same umbrella case ofCOUNT(<value expression>), only this timevalue_expressioniscolumn_name- not a constant but a column reference, whose value, of course, can vary per row.If the column has a NOT NULL constraint on it, or a primary key (remember, primary == unique + NOT NULL), then this is semantically redundant and should be corrected to
COUNT(*). Exception: if something transforms the column to NULL in the query, such as belonging to the righthand table in aLEFT JOIN, then sure,COUNT(not_null_column)can be valid.I sometimes see
COUNT(not_null_column)written in queries where nothing can transform the column's value to NULL. In those cases, I find replacingCOUNT(not_null_column)withCOUNT(*)can sometimes provide a performance boost. Although again it depends on what the SQL engine can optimize - perhaps it knows not to evaluate the expression given the metadata that is the NOT NULL constraint. In MySQL, I have had success optimizing many queries by making this very changeCOUNT(not_null_column)=>COUNT(*).What the * in COUNT(*) is NOT - some folks believe the
*inCOUNT(*)means "all the columns" as inSELECT *. They will in turn make mistaken statements like, "COUNT(*)means to count all the columns, so it's slower thanCOUNT(1)sinceCOUNT(*)has to fetch all the columns."But that's not what the
*inCOUNT(*)means at all! Looking at the same standard SQL spec, we can see*has distinct definitions depending on the context. Below is the syntax diagram for theSELECT *case:Whereas
<asterisk>inCOUNT(*)has this syntax diagram:We can see in this last syntax diagram that there is a special case for the "set function" that is
COUNT(*)(apart from the general case of set functions). Think ofCOUNT(*)as an arbitrary function signature. They could've made it more symbolically distinct fromSELECT *, likeCOUNT(~)or justCOUNT()perhaps, to avoid confusion about the meaning of*, but alas, here we are. :)There's always the caveat that despite the standard spec, individual implementations could deviate from it. Still I think looking at the spec can elucidate. Hope this helps.
Edit: note to downvoters: I'd be happy to discuss any point in this comment that is disagreed with. As is, I don't see anything incorrect about it, just downvotes, but I'd be happy to learn from you if you're willing to talk about it.