Posts Tagged ‘остатки’

Храним остатки

Воскресенье, Февраль 22nd, 2009

Ржаксинский Андрей

Первая задача, с которой сталкиваются при создании хранилища – это получение баланса. Соответственно, необходимо спроектировать хранение остатков и оборотов по счетам.

Итак вводная. Банк из top 100, специализируется на розничном бизнесе с разветвленной сетью отделений решил внедрить хранилище на SAP BW. В банке 20 филиалов плюс центральный офис, открыто 400 тыс счетов, в день проходит 200-400 тыс документов (в среднем 300 тыс), затрагивая 30-70 тысяч счетов в день (в среднем 50 тыс). Объемы зависят от дня месяца.

Необходимо принять решение о том как хранить обороты/остатки, чтобы выполнялись такие требования:
– быстрая скорость выборки;
– грануляция данных до уровня движения по 1 аналитическому счету за 1 день;
– возможность выверки и быстрого получения баланса, изменения сальдо по конкретному счету;
– обеспечить быструю работу BEX.

Т.к. проектируется OLAP система, то вопрос объема хранения данных стоит на последнем месте, а скорость выборки на самом первом.  В то же время, слишком раздутые таблицы будут замедлять выборку по ним. Для каждого варианта напишу годовой прирост по записям (исходя из 260 раб. дней) и оценки производительности.

Первый вопрос – как храним записи об остатках?
1 вариант – храним только счета, по которым были движения. Ключи:
ФИЛИАЛ
СЧЕТ
ДАТА ОПЕРАЦИИ

Достоинства и недостатки: маленький объем хранения, быстрая загрузка, медленная выборка. При выборе значений при помощи ABAP необходимо использовать выбор максимальной даты остатка, меньшей или равной текущей. В BEX – спецагрегацию “последнее значение остатка”.  Годовой прирост 260*50 тыс. =  13 мил. записей .

2 вариант – храним записи обо всех счетах ежедневно, даже если остаток не менялся или нулевой. Ключи:
ФИЛИАЛ
СЧЕТ
ДАТА ОПЕРАЦИИ

Достоинства и недостатки: большой объем хранения, медленная загрузка, быстрая выборка.  Можно хранить рассчитанные валютные эквиваленты на каждый день, убрав тем самым, переоценку во время работы с остатками.  Со временем начнутся проблемы с администрированием большой таблицы.  Необходимо сразу делать партиционирование на уровне БД и агрегаты. Запросы выполняются точно по ключу, без операций с диапазоном дат, что позволяет быстро выбирать остатки.  Но необходимо хранить ежедневные остатки, даже за выходные дни, т.к. начало или окончание отчетного периода может попасть на воскресенье.  Годовой прирост 365*400 тыс. =  146 мил. записей если хранятся нерабочие дни. Или 260*400 тыс. =  104 мил. записей если реализован механизм корректировки дат отчета на рабочие дни. Это число может быть ещё уменьшено, если не хранить нулевые остатки, это может снизить объем хранения ещё на 30%.

3 вариант – храним диапазон действия остатка. Ключи:
ФИЛИАЛ
СЧЕТ
ДАТА АКТУАЛЬНОСТИ ОСТАТКА С
ДАТА АКТУАЛЬНОСТИ ОСТАТКА ПО (не ключ)

Достоинства и недостатки: маленький объем хранения, требуются дополнительные ресурсы при загрузке, достаточно быстрая выборка.   После загрузки остатков необходимо провести перерасчет временного ряда datefrom, dateto. С датой открытия диапазона ‘01.01.1000’, закрытием ‘31.12.9999’.  При выборе сальдо необходимо ограничивать датой отчета 2-мя временными границами. Этот вариант немного медленнее 2-го варианта, но не несет его недостатков  Годовой прирост маленький, как и в 1-м случае.

Второй вопрос – как обеспечить дельты и корректировки задним числом?

Хранилище живет отдельно от основного опердня.  Объем дельты может быть как дневной, так и 15-минутный. Всё зависит от необходимости в получении оперативных отчетов и допустимого запаздывания.  Не все операционные дни могут обеспечить четко выгрузку только измененных счетов за последний час. Возможны дублирования одних и тех же счетов. Также актуальна проблема проводок задним числом, особенно в начале календарного года.

Если данные сразу ложить в куб, то возникнет проблема с задвоением остатков.  Поэтому здесь поможет ODS объект. За счет журнала мы избавляемся от задвоения записей. Данные в таблицах ODS хранятся в избыточном развернутом виде. Это облегчает отладку загрузки, позволяет визуально сравнивать отчеты и строить запросы стандартными gui средствами, быстрее, чем через просмотр данных куба. Кроме того, в случае с 3-м вариантом хранения остатков, можно реализовать трансформацию ODS -> ODS, для перестроения временного ряда.

Но ODS сильно хромает в плане производительности.  И запросы лучше строить на кубе. Поэтому необходимо реализовать загрузку ODS->куб. Причем если сделать куб точно таким же, как ODS, внести те-же инфообъекты и атрибуты навигации, то можно безболезненно переносить отлаженные BEX запросы из ODS на куб. Единственная возможная проблема – отсутствие объекта 1rownum в кубе, но это решается созданием в системе показателя, куда будет присваиваться константа 1 в ODS и агрегация в кубе позволит безболезненно заменить стандартный 1rownum.

Если принять 3 вариант хранения остатка, то имеет смысл в кубе сделать 2 измерения отдельно для datefrom и dateto, причем они должны быть там единственными признаками, что позволит включить “измерение позиций” в свойствах измерений. В куб будут писаться не dim, а сразу sid значения времени, что положительно скажется на производительности.

Описанный здесь вариант имеет свои недостатки:
-увеличенное время загрузки и доступности данных для отчетов;
-постоянно растущий журнал ODS, который необходимо администрировать и чистить;

Третий вопрос – какой потенциал для увеличения производительности?

Здесь сложно сказать что-то определенное. Необходимо рассматривать конкретные ситуации.

Стоит обратить внимание на партиционирование таблицы фактов в кубе на уровне БД. Необходимо использовать стандартное разделение по атрибуту времени.

В ODS можно переопределить на уровне БД таблицы журналов и активных данных, добавив принудительное партиционирование по диапазону какого-либо значения.
Но здесь можно рассчитывать на ощутимый прирост только если физически данные будут храниться на разных дисковых массивах.  Сейчас практически везде используется единый большой RAID, который и так обеспечивает размазывание данных по нескольким дискам. Поэтому партиционирование становится просто ещё одним индексом.  По моим замерам даже такая оптимизация добавляет 5-7% к скорости извлечения данных.

Ещё одним способом ускорить выборки является физическое разбиение данных по нескольким кубам и объединение их в мультипровайдер. Этот путь имеет хороший потенциал для оптимизации и экспериментов.  Помимо стандартного разбиения по календарным годам/кварталам/месяцам можно подумать и разбить, к примеру, по балансовым счетам.

Анализируя банковские полупроводки можно прийти к выводу, что ряд балансовых счетов встречаются в корреспонденции наиболее часто. К примеру транзитные счета могут встречаться при проводках, выгружаемых из внешних систем, при массовых перечислениях и разбросках средств. В отдельных случаях движения по таким балансовым счетам может составлять до 30% от общего числа. Это делает неэффективным выборку по балансовым счетам, к примеру в головном банке и такая картина не наблюдается в остальных филиалах. Если разделить такие остатки по различным кубам, сделать сепарацию по балансовым счетам, то тот же Oracle более качественно соберет статистику по таблицам. В итоге это опять же повлияет на общую производительность. Дробить имеет смысл вплоть до ограничения данных под группу конкретных отчетов.

Но всё же стоит понимать, что любый подобные “улучшения”, увеличивающие скорость выборки, итого замедляют саму загрузку данных и необходимо искать компромиссы.