This task is actually scientific ( the packaging problem or its type), and math.stackexchange may be better suited :)
My solution is implemented in two stages (there are so many problems with optimization) - find the initial solution and try to clarify it.
Original solution:
ServerName GroupNo TotalSizeGB ---------- ----------- ----------- Server1 3 123.45 Server2 3 234.56 Server3 2 345.67 Server4 1 456.78 Server5 2 567.89 Server6 1 678.90 Server7 3 789.01 Server8 3 890.12 Server9 1 901.23 Server10 2 1023.35 GroupNo GroupSizeGb ----------- ----------- 1 2036.91 2 1936.91 3 2037.14
Optimized:
ServerName GroupNo TotalSizeGB ---------- ----------- ----------- Server1 3 123.45 Server2 3 234.56 Server3 2 345.67 Server4 1 456.78 Server5 3 567.89 Server6 1 678.90 Server7 2 789.01 Server8 2 890.12 Server9 1 901.23 Server10 3 1023.35 GroupNo GroupSizeGb ----------- ----------- 1 2036.91 2 2024.80 3 1949.25
Unfortunately, I was not able to configure it to SQLFiddle, since explicit transactions are used.
set nocount on -- Parameters declare @nGroups int, -- Number of groups to split servers to @tolerance float, -- let say 0.0 ... 0.1 (0.1 mean that (+/-)10% deviation allowed from target group size) @nTries int, -- refinement tries 100, 1000, 10000 or as much as you can wait if you are not satisfied with initial solution @mFactor float, -- refinement param 0.0 ... 1.0 @tolerance2 float -- let say 0.1 ... 0.3 set @nGroups = 3 set @tolerance = 0 set @nTries = 1000 set @mFactor = 0.3 set @tolerance2 = 0.3 -- Initial Data create table #Servers (ID int identity, ServerName sysname, TotalSizeGB decimal (12,2), primary key clustered(ID)) insert into #Servers (ServerName, TotalSizeGB) values ('Server1',123.45), ('Server2',234.56), ('Server3',345.67), ('Server4',456.78), ('Server5',567.89), ('Server6',678.90), ('Server7',789.01), ('Server8',890.12), ('Server9',901.23), ('Server10',1023.35) create table #Groups (GroupNo int not NULL, primary key clustered (GroupNo)) insert into #Groups (GroupNo) select N from (select row_number() over (order by @@spid) from sys.all_columns) S(N) where N <= @nGroups create table #ServerGroups (ServerID int not NULL, GroupNo int not NULL, primary key clustered(ServerID)) create index #IX_GroupServers_GroupNo on #ServerGroups (GroupNo) declare @srvCnt int, @grSize decimal (12,2), @grNo int, @grSz decimal (12,2), @srvID int select @srvCnt = count(1), @grSize = sum(TotalSizeGB) / @nGroups from
I suggest starting with @nTries = 0 and a reasonable @tolerance (e.g. 0.1, 0.05).