This is the fastest that I can think of:
select t.*, row_number() over (order by (select NULL)) as seqnum
from ((select * from A) union all
(select * from B)
) t;
Two things. First this uses union all
rather than union
-- so duplicates are not removed. This speeds up the query if duplicate removal is not necessary.
Second, it uses order by (select NULL))
. In my experience, this seems to assign a sequential number on output without actually incurring the overhead of a sort. This is strictly based on my experience. I have not yet found SQL Server documentation that explains this. But, I have used it in the past successfully.