Балансировка потоков в Oracle

При параллельной загрузке данных в хранилище, чтобы уменьшить время общей загрузки таблиц часто применяется динамическая балансировка по потокам. То есть, разные задачи группируются в какое то количество потоков (обычно константа, но может также меняться в зависимости от разных условий). Выходит что на основании веса разбиваем задачи на несколько потоков, желательно чтобы  максимальный суммарный вес одного потока был минимальным. Итак получается: Задача о ранце (рюкзаке) (англ. Knapsack problem) . 
Но приведу более простой алгоритм, может и не самый эффективный, но простой и удобный в реализации.
Весом могут быть разные параметры,  например:
  • время загрузки в прошлый раз
  • количество строк
  • размер таблицы
  • статистике
Балансировку можно делать каждый раз, или в какой то период, и каждый раз задача может попадать в разные потоки.

Реализация алгоритма на Oracle:
WITH 
--элементы с весом или продолжительностью
ITEMS AS
          (SELECT 1 AS ID, 100 AS WEIGHT FROM DUAL UNION ALL
           SELECT 5 AS ID, 100 AS WEIGHT FROM DUAL UNION ALL
           SELECT 6 AS ID, 100 AS WEIGHT FROM DUAL UNION ALL
           SELECT 2 AS ID, 1   AS WEIGHT FROM DUAL UNION ALL
           SELECT 3 AS ID, 1   AS WEIGHT FROM DUAL UNION ALL
           SELECT 4 AS ID, 1   AS WEIGHT FROM DUAL),
--считаем общую сумму, и накопительную
ITEMS1 AS
 (SELECT ITEMS.*,
     (SUM(ITEMS.WEIGHT) OVER(PARTITION BY 1)) AS SUM_ALL,
     (SUM(ITEMS.WEIGHT) OVER(PARTITION BY 1 ORDER BY WEIGHT ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)) SUM_CURR
 FROM   ITEMS)
--результат в поле V$FLOW
SELECT ID,
    WEIGHT,
    SUM_ALL,
    SUM_CURR,
    WIDTH_BUCKET(SUM_CURR,0,SUM_ALL,4) V$FLOW --количество потоков = 4
FROM   ITEMS1

В результате получим:
IDWEIGHTSUM_ALLSUM_CURRV$FLOW
3130311
2130321
4130331
51003031032
11003032033
61003033035

Комментарии