Pregunta

Soy consciente de que probablemente no es una solución "perfecta" a mi pregunta (esto suena como una variación de la mochila o el problema de embalaje Bin), pero aquí está mi escenario:

Quiero dividir una lista de tablas de bases de datos SQL en n (digamos 7) montones más o menos del mismo tamaño (para que pueda difundir algunas tareas de mantenimiento más o menos igual en toda una semana).

Digamos que tengo 100 mesas (esto podría ser mayor o menor, pero no es probable superior a 5000), que van desde Tamaño 1 a 10 millones (tablas más grandes son mucho menos comunes, por supuesto).

Mi idea original era ordenar las tablas alfabéticamente (pseudo-aleatoria) y luego caminar a través desde el principio, de pasar al siguiente grupo cuando el total es superior a la suma (Tamaño) / 7. Para algunas bases de datos, esto probablemente funcionan bien, pero si dos tablas gigantes son uno al lado del otro, entonces esto lo convierte en grupos muy desiguales. (Esto no es tan improbable que parezca, debe tener en cuenta dos mesas enormes, account_history y Account_History_Archive).

¿Hay técnicas generalmente aceptadas para esto, que dan resultados "buenos" con una variedad de datos de origen? Me inclino hacia una técnica más sencilla en lugar de una agrupación más preciso (si el mantenimiento corre un poco más largo en algunos días que otros, no es que de gran cosa).

¿Fue útil?

Solución

¿Qué hay de la clasificación de las tablas por tamaño, a continuación, para cada mesa, lo puso en el día en que tiene actualmente el número total más corta de filas en ella? Este medio de los mayores 7 mesas serán distribuidas en los primeros días. A continuación, el octavo más grande irá con el más pequeño de los primeros 7, etc. Tendrá que continuar para llenar el día con la menor cantidad de trabajo programado a la misma.

Cuando las tablas de referencia pequeños terminan finalmente probablemente no hay mucha diferencia.

Se podría inventar escenarios en los que esto no es bueno, pero espero que funcionará en la práctica sin ser demasiado complicado.

Otros consejos

No sé cómo este se clasifica en la buen código escala, pero una solución que me gustaría persigo es poner la lista de trabajos en una cola de prioridad, ordenadas por la más costosa, y el trabajador contenedores en otra cola de prioridad, ordenados por menos trabajo asignados, y luego simplemente pop trabajos fuera de una cola y se asignan a la parte superior (menos ocupado) bin trabajador, hasta que no quede de trabajo.

Sólo como referencia, así es como fui sobre esto. Quería poner el "Cubos" en una tabla persistió y única "Recalcular" ellos cada 2 semanas. De lo contrario, temía que si computé estos cubos cada día, una tabla podría saltar de un cubo a otro. Sin embargo, quería volver a calcular cada cierto tiempo para el esquema y DDL modificaciones. He aquí que el fragmento de código.

-------------------------------------------------------------------------------------
--Get the total table size (by rows)
-------------------------------------------------------------------------------------


if object_id('tempdb..#Space') is not null
drop table #Space

SELECT 
    TableName = t.NAME,
    Schem = s.name,
    Pages = sum(a.total_pages),
    Grp = row_number() over (order by sum(a.total_pages) desc)
INTO #Space
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.name


-------------------------------------------------------------------------------------
--split the tables into 7 buckets by:
    --updating the Grp to the Grp with the lowest cumulative sum of all members by
    --ordering by the current cumulative sum of all members
-------------------------------------------------------------------------------------

declare @ct int = 8


while @ct <= (select max(Grp) from #Space)
begin

    update S
    set Grp = (select top 1 Grp from #Space where Grp < 8 order by sum(Pages) over (partition by Grp) asc)
    from #Space S
    where S.Grp = @ct

    set @ct = @ct + 1

end


insert into AdminTools..TableSpace (TableName
                                    ,Schem
                                    ,Pages
                                    ,Grp
                                    ,GrpPages
                                    ,LoadDate)
select 
    TableName
    ,Schem
    ,Pages
    ,Grp
    ,GrpPages = sum(Pages) over (partition by Grp)
    ,LoadDate = getdate()
from #Space
end
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top