The second query is more efficient. Although with the current number of tables, you won't feel a performance increase, but as you add tables you may start to notice (although I doubt it given the size of your tables).
I tested this by created my own set of three tables, each with 2500 records and three columns: an ID and two random numbers.
IF OBJECT_ID('[dbo].[x1]','U') IS NOT NULL DROP TABLE [dbo].[x1]
IF OBJECT_ID('[dbo].[x3]','U') IS NOT NULL DROP TABLE [dbo].[x3]
IF OBJECT_ID('[dbo].[x2]','U') IS NOT NULL DROP TABLE [dbo].[x2]
CREATE TABLE [dbo].[x1] ( [TableID] INT IDENTITY(1, 1), [a] INT, [b] INT )
CREATE TABLE [dbo].[x2] ( [TableID] INT IDENTITY(1, 1), [a] INT, [b] INT )
CREATE TABLE [dbo].[x3] ( [TableID] INT IDENTITY(1, 1), [a] INT, [b] INT )
-- TEMPORARY TABLE CREATION
IF OBJECT_ID('tempdb..[#RandomNumbers]') IS NOT NULL DROP TABLE [#RandomNumbers]
IF OBJECT_ID('tempdb..[#RandomNumbers2]') IS NOT NULL DROP TABLE [#RandomNumbers2]
IF OBJECT_ID('tempdb..[#ids]') IS NOT NULL DROP TABLE [#ids]
-- GENERATING TWO SETS OF RANDOM NUMBERS
CREATE TABLE [#ids] ( [RandSeq] INT )
SET NOCOUNT ON
DECLARE @startNum INT
SELECT @startNum = 1000
BEGIN WHILE ( @startNum <= 9999 ) BEGIN
INSERT INTO [#ids]
( [RandSeq] )
SELECT @startNum
SELECT @startNum = @startNum + 1
END RETURN END
SET NOCOUNT OFF
GO
CREATE TABLE [#RandomNumbers] ( [TableID] INT IDENTITY(1, 1), [vipRand] INT )
INSERT INTO [#RandomNumbers] ( [vipRand] ) SELECT [RandSeq] FROM [#ids] ORDER BY NEWID()
CREATE TABLE [#RandomNumbers2] ( [TableID] INT IDENTITY(1, 1), [vipRand] INT )
INSERT INTO [#RandomNumbers2] ( [vipRand] ) SELECT [RandSeq] FROM [#ids] ORDER BY NEWID()
-- POPULATING TEST TABLES
INSERT INTO [dbo].[x1] ( [a], [b] )
SELECT TOP 2500 [a].[vipRand], [b].[vipRand]
FROM [#RandomNumbers] a INNER JOIN [#RandomNumbers2] b ON [a].[TableID] = [b].[TableID]
ORDER BY NEWID()
INSERT INTO [dbo].[x2] ( [a], [b] )
SELECT TOP 2500 [a].[vipRand], [b].[vipRand]
FROM [#RandomNumbers] a INNER JOIN [#RandomNumbers2] b ON [a].[TableID] = [b].[TableID]
ORDER BY NEWID()
INSERT INTO [dbo].[x3] ( [a], [b] )
SELECT TOP 2500 [a].[vipRand], [b].[vipRand]
FROM [#RandomNumbers] a INNER JOIN [#RandomNumbers2] b ON [a].[TableID] = [b].[TableID]
ORDER BY NEWID()
The next step is to test the two queries you laid out in the question. Make sure you turn on the option to Include Actual Execution plan. We'll also turn on STATISTICS so you can see the number of reads, as well as wiping the cache between queries so we see the true reads.
SET STATISTICS IO ON
--WIPE CACHE
USE [TestDB];
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
SELECT [TableID], MIN([a]), CONVERT(NUMERIC(19, 2), SUM([b]))
FROM ( SELECT [TableID], MIN([a]) AS [a], SUM([b]) AS [b]
FROM [dbo].[x1]
GROUP BY [TableID]
UNION
SELECT [TableID], MIN([a]) AS [a], SUM([b]) AS [b]
FROM [dbo].[x2]
GROUP BY [TableID]
UNION
SELECT [TableID], MIN([a]) AS [a], SUM([b]) AS [b]
FROM [dbo].[x3]
GROUP BY [TableID] ) AS u
GROUP BY [u].[TableID]
--WIPE CACHE
USE [TestDB];
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
SELECT [TableID], MIN([a]), CONVERT(NUMERIC(19, 2), SUM([b]))
FROM ( SELECT [TableID], [a], [b]
FROM [dbo].[x1]
UNION
SELECT [TableID], [a], [b]
FROM [dbo].[x2]
UNION
SELECT [TableID], [a], [b]
FROM [dbo].[x3] ) AS u
GROUP BY [u].[TableID]
If you run these together, you should be able to compare both the reads and the execution plans. Notice first that they are using the same number of logical and physical reads, so we're good there. But look at the execution plans. There is a pretty distinct difference, caused by the number of calculations that are done. In the first query, you are running a set of calculations on the data, and then doing it a second time. By only doing one calculation, the second query has to go through less steps, so you're being more efficient and returning the same results. But only by a little. You're looking at a relative query cost that doesn't show much differentiation, hence my starting comment that it's not that big of a deal either way.
But we can make your query more efficient by changing the UNIONs to UNION ALLs. If you run the next code block with the previous two, you can again see the differences.
--WIPE CACHE
USE [TestDB];
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
SELECT [TableID], MIN([a]), CONVERT(NUMERIC(19, 2), SUM([b]))
FROM ( SELECT [TableID], [a], [b]
FROM [dbo].[x1]
UNION ALL
SELECT [TableID], [a], [b]
FROM [dbo].[x2]
UNION ALL
SELECT [TableID], [a], [b]
FROM [dbo].[x3] ) AS u
GROUP BY [u].[TableID]
You'll notice that the execution plan reduces the number of steps, choosing to CONCATENATE the tables rather than MERGE JOIN. In the first two queries, you are specifying a distinct selection of records by using UNION, which you don't really need. UNION ALL will be faster because it doesn't need to sort and join the results to find that distinct selection. For a brief overview, see this question.