Один подход к распараллеливанию приложений использующих Oracle базу данных

добавлено: 29 мар 13
понравилось:0
просмотров: 1868
комментов: 0

теги:

Автор: AlexeiF


Описание проблемы.

Имеется огромная база данных D1, где хранятся данные загружаемые каждый день и все таблицы имеет партиции по дням. Также имеется другая база данных D2, где хранятся обработанные данные из первой базы для создания различных репортов и представления обработанных данных через DUI или в Интернете.
В данном конкретном случае надо загрузить из таблиц D1 данные в таблицу на D2, причем бизнес логика программы предполагает, в своей основе, построения цикла и выборку данных из JOIN двух таблиц из D1. Ну, скажем что-то в таком виде:
	
Parameter1:=<1>
LOOP  < parametr2= 1,2,3,4,5,6>
INSERT INTO T_SUM
….
SELECTGROUP FUNCTION
...
FROM T1@D1 T1, T2@D1 T2
WHERE
…
T1.PROD_ID=T2.PROD_ID
AND 
T1.TRADE_TIME  between parameter1 and pararameter1+pararameter2
…..
;
pararameter1:= pararameter1+pararameter2
…….
COMMIT;
End LOOP;

Т.к. прежде всего у нас имеется сложный JOIN двух таблиц на D1, функция группировки и INSERT на D2, то Oracle наверняка перепишет SQL на две части: сначала выберет данные из таблицы T1, потом из таблицы T2 и потом уже будет уже делать JOIN этих таблиц на D2 с использованием функции группировки. Хотя таблицы Т1 и Т2 не так уже и велики, Т1 где-то порядка 15 млн. рядов и Т2 порядка 7 млн. рядов все же копирование данных на D2 займет время. Но, самое большое время занимает сам по себе JOIN, который в данном конкретном случае возвращает порядка 90 млн. записей, которые получаются используя HASH JOIN двух таблиц, да еще нужно для всех этим 90 млн. записей применить групповую функция, что приводит к дополнительному использованию различного вида сортировок и как результат активному использованию сегментов временного табличного пространства. В конкретном примере 25 Gb временного табличного пространства не хватало для обработки всех данных и программа вываливалась, проработав более 20 часов.

РЕШЕНИЕ.

Основная идея решения данной проблемы состоит в разделении нашей апллкации на отдельные независимые части и обработка данных параллельно – APPLICATION PARTITIONS. Кроме того, разделив данные на независимые части мы уменьшаем объем данных для JOIN и обработки групповой функцией, мы еще и можем использовать намного эффективнее SORT AREA в памяти ORACLE. Так, если, мы будем обрабатывать все в одной TREAD нам будет доступно только 2 Gb КЭШи, если же будем использовать 4 THREAD, каждая из которых будет отдельной сессией в ORACLE, нам будет доступны 8 Gb кэш. Это все как раз и дает огромный выигрыш в скорости обработки данных и получении результата в течении 15 минут, без использования дискового пространства для организации временных сегментов и проведения сортировки и хеширования данных.
Как видно из самого JOIN у нас идет установление связи между двумя таблицами по ключу PROD_ID в виде

T1.PROD_ID=T2.PROD_ID

Это ключевой момент как мы можем разделить нашу аппликация на независимые части. Сделаем на базе D2 таблицы T1_HASH и T2_HASH , скажем с 4 партициями каждая, по ключу на колонку PROD_ID. Партиции будут типа HASH.
CREATE TABLE T1_HASH
(PROD_ID  NUMBER,..
)
PARTITION BY HASH(PROD_ID)
(PARTITION  TREAD_01,
PARTITION  TREAD_02,
PARTITION  THREAD_03,
PARTITION THREAD_04);

CREATE TABLE T2_HASH
(PROD_ID  NUMBER,..
)
PARTITION BY HASH(PROD_ID)
(PARTITION TREAD_01,
PARTITION TREAD_02,
PARTITION THREAD_03,
PARTITION THREAD_04);

Запускаем два независимых процесса , параллельно, и копируем данные из Т1@D1 и T2@D1 во вновь созданные таблицы T1_HASH@D2 и T2_HASH @D2. Пример приминения HASH PARTITION приведен на Рис. 1.:

Картинка с другого сайта.

Где ряды со значением PROD_ID = 1,5,9 …. будут, находится в партиции THREAD_01, а ряды со значение PROD_ID=3,7,11 …в партиции THREAD_03 и т.д.
Т.о. мы можем теперь стартовать 4 процесса параллельно, как показано на Рис. 2.

Картинка с другого сайта.

Сама аппликация будет использовать номер THREAD как параметр, скажем в таком виде:
Parameter1:=<1>
LOOP  < parametr2= 1,2,3,4,5,6>
INSERT INTO T_SUM
….
SELECTGROUP FUNCTION
...
FROM T1_HASH PARTITION (THREAD_&1)  T1, T2_HASH PARTITION (THREAD_&1) T2
WHERE
…
T1.PROD_ID=T2.PROD_ID
AND 
T1.TRADE_TIME  between parameter1 and pararameter1+pararameter2
…..
;
pararameter1:= pararameter1+pararameter2
…….
COMMIT;
End LOOP;


ДОПОЛНЕНИЯ

1.Как было указанно выше, основной идей разделения аппликации на партиции была связка двух таблиц ,к примеру, по ключу PROD_ID. Очевидно, что при JOIN ДВУХ и более таблиц по большему числу колонок необходимо хеширование по всем ключам связи. К примеру, если мы имеем JOIN в виде
……..
T1.PROD_ID=T2.PROD_ID
AND
T1.CUSTOMER_NAME=T2.CUSTOMER_NAME
………
То таблицы на D2 будут выглядеть следующим образом:
CREATE TABLE T1_HASH
(PROD_ID  NUMBER,
CUSTOMER_NAME VARCHAR2,..
)
PARTITION BY HASH(PROD_ID, CUSTOMER_NAME)
(PARTITION  TREAD_01,
PARTITION TREAD_02,
PARTITION THREAD_03,
PARTITION THREAD_04);

CREATE TABLE T2_HASH
(PROD_ID  NUMBER,
CUSTOMER_NAME VARCHAR2,..
)
PARTITION BY HASH(PROD_ID, CUSTOMER_NAME)
(PARTITION TREAD_01,
PARTITION TREAD_02,
PARTITION THREAD_03,
PARTITION THREAD_04);

2. Идея Application Partition для JOIN , скажем 3 таблиц, при связывании их по разным ключам приведена на Рис.3

Картинка с другого сайта.
Рис.3
Здесь исходный JOIN был в виде
INSERT INTO T_SUM
….
SELECTGROUP FUNCTION
FROM T1@D1 T1, T2@D1 T2,T3@D1 T3
WHERE
…
T1.PROD_ID=T2.PROD_ID
AND 
T2.ORDER_ID=T3.ORDER_ID
AND
TRADE_TIME  between parameter1 and pararameter1+pararameter2
…..
;
pararameter1:= pararameter1+pararameter2
….

Если у кого-то возникнут любые вопросы по конкретному применению этой идеи буду рад помочь.

Комментарии




Необходимо войти на сайт, чтобы оставлять комментарии