TIME-SERIES. ****. ПРОДОЛЖЕНИЕ.

добавлено: 01 янв 16
понравилось:0
просмотров: 2014
комментов: 0

теги:

Автор: AlexeiF

Данный блог есть продолжение предыдущего: "TIME-SERIES. ПАРТИЦИИ. NO INDEX. ПАРАЛЛЕЛЬНОЕ ЧТЕНИЕ."
В дальнейшем материале пойдет обсуждение различных идей по создания партиций и организации возможностей получения данных без особого изменения программ по выборы данных (SELECT ...) с пользованием вышеуказанных идей по разделения огромных таблиц на партиции по времени заполняемых в реальном режиме.
Один из подходов описан в первой части и состоит в создании LIST PARTITION для основной таблицы по ключу PART_KEY. Процесс заполнения такой таблицы можно явным образом упростить если использовать возможность ORACLE по созданию партиции на псевдо-колонку (Pseudocolumn)
CREATE TABLE	SQH_AF1
(
.....
......
  part_key                     AS (round((to_char(CREAT_REC_TIME,'SSSSS')- 25200)/(57600 - 25200 )*5999,0)+1)
)
PARTITION BY LIST (part_key)
(
PARTITION P_1  VALUES(1)
...
...
);

В данном случае предполагается что заполнение таблицы будет начато с 7:00 и закончится в 16:00. Количество партиций - 6000. Разумно дополнить таблицу SQH_AF1 двумя дополнительными партициями:
alter table SQH_AF1 add partition P_NULL values( NULL);
alter table SQH_AF1 add partition P_OTHER values(DEFAULT);

Это ,по-сути дела, время работы TRADING SYSTEM в системе продаж стаков/опционов и т.д. В дальнейшем данные будут перекаченны в Datawarehouse, а данные из системы удаляются и система готова для следующего дня.

Выше был обозначен подход по чтению данных использую принцип распараллеливания, но в реальности написанные приложения не хотелось бы менять и оставить чтение используя предикат BETWEEN по времени CREAT_REC_TIME не используя индекс на данную колонку. Особенно это актуально для работы с Oracle Exadata Database Machine. Для поддержки такого подхода необходимо создать управляющую таблицу и VIEW, которые позволят правильно использовать партиции для чтения. Итак управляющая таблица
CREATE TABLE AF_CTL
(
  CREAT_REC_TIME  DATE,
  PART_KEY    NUMBER, 
  CONSTRAINT AF_CTL_PK
  PRIMARY KEY
  (CREAT_REC_TIME)
  ENABLE VALIDATE
)
ORGANIZATION INDEX
;

Пример данных в такой таблицы:
CREAT_REC_TIME			PART_KEY
_____________________ 	________
12/16/2015 4:32:19 PM	159
12/16/2015 4:32:20 PM	159
12/16/2015 4:32:21 PM	159
12/16/2015 4:32:22 PM	159
12/16/2015 4:32:23 PM	160
12/16/2015 4:32:24 PM	160
12/16/2015 4:32:25 PM	160
12/16/2015 4:32:26 PM	160
12/16/2015 4:32:27 PM	160

и VIEW

create or replace view SQH_AF_v
as
select a.* from SQH_AF1 a, af_ctl b
where a. CREAT_REC_TIME= b.CREAT_REC_TIME
and a.part_key= b.part_key;

Понятно , что управляющую таблицу AF_CTL нужно готовить каждый день для следующего дня используя ТУЖЕ формулу для вычисления PART_KEY по CREAT_REC_TIME, в данном случае это part_key=((round((to_char(CREAT_REC_TIME,'SSSSS')- 25200)/(57600 - 25200 )*5999,0)+1)) для каждой секунды от 7:00 до 16:00. Ну или заполним один раз эту таблицы менять в ней только ДЕНЬ,МЕСЯЦ и ГОД.

Используя view SQH_AF_v вместо таблицы мы легко и БЫСТРО находим данные по времени. ORACLE через view определяет необходимую партицию, что видно в EXPLAIN PLAN для SELECT запроса.
SELECT *
  FROM SQH_AF_v 
 WHERE CREAT_REC_TIME  between TO_DATE('12/16/2015 16:21:50', 'MM/DD/YYYY HH24:MI:SS') and TO_DATE('12/16/2015 16:30:45', 'MM/DD/YYYY HH24:MI:SS')

Plan
SELECT STATEMENT  ALL_ROWS Cost: 2,049,852  Bytes: 276  Cardinality: 1  					
	9 HASH JOIN  Cost: 2,049,852  Bytes: 276  Cardinality: 1  				
		6 PART JOIN FILTER CREATE SYS.:BF0000 Cost: 2,049,852  Bytes: 276  Cardinality: 1  			
			5 NESTED LOOPS  Cost: 2,049,852  Bytes: 276  Cardinality: 1  		
				2 STATISTICS COLLECTOR  	
					1 INDEX RANGE SCAN INDEX (UNIQUE) AF_CTL_PK Cost: 2  Bytes: 11,770  Cardinality: 535  
				4 PARTITION LIST ITERATOR  Cost: 2,049,850  Bytes: 254  Cardinality: 1  Partition #: 6  Partitions determined by Key Values	
					3 TABLE ACCESS STORAGE FULL TABLE SQH_AF1 Cost: 2,049,850  Bytes: 254  Cardinality: 1  Partition #: 6  Partitions determined by Key Values
		8 PARTITION LIST JOIN-FILTER  Cost: 2,049,850  Bytes: 64,723,010  Cardinality: 254,815  Partition #: 8  Partitions accessed #:BF0000			
			7 TABLE ACCESS STORAGE FULL TABLE SQH_AF1 Cost: 2,049,850  Bytes: 64,723,010  Cardinality: 254,815  Partition #: 8  Partitions accessed #:BF0000		

Данный подход к построению партиций очевидным образом не учитывает колебания скорости заполнения таблицы в течении дня. Мало того, что процесс заполнения носит стохастический характер, но он еще и явно не стационарен, т.е, в основном, в районе 9:00 и 14:00 имеются пики активности и где-то с 12:00 до 13:00 спад активности. Это будет приводить, к тому, что т.к. у нас партиции разделены по времени на равные промежутки, то количество рядов в каждой партиции будет существенно отличаться, что приведет в свою очередь к существенной разнице по времени запроса для пиковых времен к непиковым.
Идея состоит том чтобы каким-то образом уравнять количество рядов в каждой партиции, за счет длительности времени разделения на партиции. Т.е. N(i) = Rate[t(i+1) - t(i)] ~ N(j) = Rate[t(j+1) - t(j)] ~ N(Average) = NumberOfRowsForWholeDay/NumberOfPartitions. Исходя из этой идеи возможны два подхода:
1. Взять за основу некий "типичный" день, посчитать для него величины N(Average) и Rate(t). Далее исходя из этих значений несложно сделать программу по заполнения управляющей таблицы, где очевидным образом интервалы времени по разным партициям будут разные и неким образом партиции будут отражать поведение Rate(t). Для пиковых значений интервалы партиций будут короче ,а для непиковых длиннее. Понятно что заполнение основной таблицы с данными надо уже будет на основании значений из управляющей таблицыгде он основании времени CREAT_REC_TIME будет определятся PART_KEY, для каждого значения.
2. Второй подход состоит в разработки некого блока "предсказания" как будет себя вести Rate(t) на основе реальных статистических данных на текущий момент и на основании этого заполнять управляющую таблицу.

Комментарии




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