Generally, you can expect that the row count reported will correspond to the number of rows returned to the caller (and to the (x row(s) affected)
message in SQL Server Management Studio in the case of a top-level query).
However, where the statement contains nested calls, such as to a scalar user-defined function, row counts generated in the (repeated) calls to the function's execution plan will be added to the total. This is an unfortunate side-effect of where the counting is done*, and the way non-inline functions are currently implemented. It has been considered not important enough to fix.
In the linked Connect item example (better formatted in the parent blog post by Guy Glanster), the total row count for the query that returns 100 rows is reported as 300, due to the single row affected by each of the two statements in the function, on each invocation.
If the function is reduced to a single statement:
RETURN CAST(@DateTimeValue AS date);
...the count is 200 (100 rows for the outer query, plus 1 row a hundred times for the function).
DBCC UPDATEUSAGE
will not affect this. Indexes and fragmentation have no bearing either. It is simply an architectural consequence, and another reason to avoid non-inline functions.
* The details are rather esoteric. Broadly, for a SELECT
query, it is the number of rows seen at the root node of the plan. There is a shared memory structure involved, and nothing you can see directly in an execution plan. When a scalar function executes, it does so in a subcontext that happens to share the structure. Perhaps this is by design, it is hard to know for sure without source code access. My feeling (as stated) is that it is an unintended side effect. For DML queries, a particular plan node is assigned the job of maintaining the rows-affected count. This can differ significantly depending on the shape of the plan (for example if an OUTPUT
clause is used, or Split-Collapse update processing is employed).