A solution to this is to get the MIN
per partition (which should just require reading the single row at the end of the index from each) and then get the MIN
of those.
One query approach for this (covered by Itzik Ben Gan here) is
SELECT MIN(m.row_id) AS row_id
FROM sys.partitions AS P
CROSS APPLY (SELECT MIN(row_id) AS row_id
FROM dbo.test_table
WHERE $PARTITION.YourPartitionFunction(YourPartitionColumn) = P.partition_number) AS m
WHERE P.object_id = OBJECT_ID('dbo.test_table')
AND P.index_id <= 1;
You haven't told us the name of your partition function or partitioning column so replace YourPartitionColumn
and YourPartitionFunction
as appropriate above (and remember to replace both references to test_table
when applying it against a different table name).
The execution plan for this should have the partition numbers returned from sysrowsets
on the outside of a nested loops and on the inside of this an ordered index scan with a seek predicate to seek into just the single partition of interest. This should be under a TOP 1
operator to stop reading from the scan after the first row is read.
If you don't see the above plan (e.g. as the column you are aggregating is nullable) a more verbose alternative is
SELECT MIN(m.row_id) AS row_id
FROM sys.partitions AS P
CROSS APPLY (SELECT TOP 1 row_id
FROM dbo.test_table
WHERE $PARTITION.YourPartitionFunction(YourPartitionColumn) = P.partition_number
AND row_id IS NOT NULL
ORDER BY row_id
) AS m
WHERE P.object_id = OBJECT_ID('dbo.test_table')
AND P.index_id <= 1;
The more verbose alternative does mean that you will potentially miss out on the message:
Warning: Null value is eliminated by an aggregate or other SET operation.
but I doubt anyone cares about seeing that.
CREATE NONCLUSTERED INDEX row_id_IX ON dbo.test_table ( row_id ASC )
is clearly not the full definition, as the table is partitioned.CREATE
that was run as it will default to partition aligning if the underlying table is partitioned but full DDL including name of partition function would be useful