Этот сайт посвящается администрированию баз данных OpenEdge Progress.
Не корысти ради, а познания для!

С уважением,
Валерий Башкатов
Сайт разработан при участии компании Progress Technologies, официального дистрибьютора Progress Software Corp. на территории стран СНГ и Латвии.

RSS RSS подписка на обновления сайта

Поиск по сайту

Лучшие материалы

Orphus System
На сайте функционирует система коррекции ошибок. Обнаружив неточность в тексте, выделите её и нажмите Ctrl+Enter



Результаты опроса: Нужны ли книги по Progress OpenEdge на русском языке? (опрос проводился с мая 2009 по ноябрь 2010)

Да, нужны. Потому что будет легче понять материал - 268
Нет, не нужны. Достаточно материалов на английском языке - 10
Не знаю, мне всё равно - 6

А знаете ли вы что..



Процедура смены структуры базы данных Progress(разбиваем БД на области)


Процедура смены структуры базы данных Progress
(разбиваем БД на области)

План:

1. Анализ существующей БД и создание нового структурного файла
   Количество и размеры томов областей
2. Dump данных
3. Dump метаданных
4. Backup существующей БД
5. Удаление существующей БД
6. Создание новой БД
   Создание новой структуры
   Копирование БД с эталона
   Загрузка метаданных
7. Load данных
8. Переиндексация БД
9. Анализ созданной БД



1. Анализ существующей БД и создание нового структурного файла

Анализ базы данных заключается в формировании отчета по состоянию таблиц и индексов БД. Данный отчет формируется по средствам утилиты Progress – dbanalys. Синтаксис утилиты выглядит так:

proutil <DBNAME> -C dbanalys > <файл>

Из отчета необходимо выделить таблицы, размер которых приближен или уже превысил 1Gb. Эти таблицы будут выделены в отдельную область данных.
Пример:

Таблица
 Записей Разм.
Мин.
 Макс  Сред. Всего
Фактор
 Фактор
 PUB.table1  18406680  1.4G  56  131  82  18406760  1  2,8
 PUB.table4  40294556  7.2G  78  13227  191  40296284  1  2
 PUB.table5  7491323  5.2G  190  1509  747  7529434  1  3,6
 PUB.table10  11540526  952.0M  50  256  86  11540661  1  2,4


Из этого фрагмента видно, что мы имеем три таблицы (table1, table4, table5) намного превысившие размер в 1Gb, и одну таблицу, приближающуюся к этому пределу. Следовательно, намечается четыре потенциальные области данных.
Для каждой области необходимо определить RPB, для этого можно использовать файл «blk-calc.xls». На основании результатов работы алгоритмов этого файла мы получаем следующую картину:
Область RPB
Table1 Area 128
Table4 Area 64
Table5 Area 128
Table10 Area 128

Оставшиеся таблицы выделяем в отдельную общую область.
RPB этой области можно также определить с помощью файла «blk-calc.xls». При этом мы используем данные не каждой таблицы, а их общие суммы. В итоге получаем значение RPB общей области равное 128.

На первый взгляд, кажется, что для анализа, выше описанной процедуры достаточно. На практике же это не совсем так.
Начну с утверждения – областей должно быть много. В первую очередь, преимущество от расселения объектов базы по отдельным секциям почувствует администратор базы при выполнении штатных процедур. Большинство таких процедур можно выполнять на уровне области. Больше областей => меньше размер каждой области => быстрее закончится “атомарная” операция => сокращаются требования к временному окну, в течении которого база должна находится в offline. Разбиение базы также может улучшить производительность при работе с ней конечных пользователей. Это трудно доказать исходя из абстрактных предпосылок, но практика подтверждает утверждение.
Конечно же, в количестве областей не стоит доходить до экстремизма. Их число должно быть ограниченным. Администратор обязан отслеживать свободное место для каждой из областей. Каноническое утверждение Дена Форемана (Dan Foreman) – в базе должно быть 24 области – чтобы список умещался на одном экране символьного клиента. В вольном переводе это звучало бы примерно так – базу стоит разбить на десяток или несколько десятков областей.
Чем более мощная машина (количество процессоров, количество физических дисков) – тем больше стоит делать областей.
“Базодробильный” процесс можно строить на следующих принципах:
1. Люкс для “монстров” – под большие таблицы выделяем отдельные области (этот принцип мы использовали в примере описанном выше). Обычно под “большими таблицами” понимают таблицы, чей объем превышает гигабайт или в которых более миллиона записей. Но такое определение, не совсем корректно. Все таблицы были когда-то маленькими. Сформулируем принцип так: большая таблица – это таблица, чей объем составляет существенный процент (скажем 20%) объема базы или области. Понятно, что выделиь в базе “монстров” можно на основе dbanalys`а.
2. Подбираем пары по “характеру” – делим все таблицы на три группы: статичные (справочники), динамичные и архивные. Статичные таблицы характеризуются тем, что они почти никогда (или очень мало) модифицируются. Основная операция с ними – чтение. Для динамичных таблиц соотношение операций чтения и модификации (включая создание и удаление записей) сопоставимо между собой. Архивные таблицы отличаются тем, что данные в них в основном только добавляются. По своей сути, архивные таблицы часто также оказываются “большими” таблицами, которые мы уже расселили. Такие характеристики таблиц из dbanalys`а не извлечешь. Нужно некоторое время понаблюдать за работой приложения, собирая в конце дня статистику из системных таблиц _TableStat и _IndexStat. Для того чтобы такая статистика была полной, база должна быть запущена с достаточно большим значением параметров –tablerangesize/-indexerangesize (1000 и 4000 будет достаточно практически для любого приложения). Если в приложении есть стадии обработки, когда в базе единовременно создается большое количество записей в разных таблицах, то эти таблицы стоит разнести по разным областям, чтобы при создании записей процессы, их создающие, не конкурировали между собой за головной блок RM- или Free-цепочках. Такие цепочки в каждой области свои.
3. Дальнейшее “измельчение” областей. Если два предыдущих подхода породили слишком мало областей, то для дальнейшего дробления базы, можно разбить таблицы на группы с примерно равным средним размером записей – чтобы для них было бы оптимальным одно и тоже значение RPB. Либо разбиваем просто в алфавитном порядке или используем любой другой волюнтаристский принцип – лишь довести количество областей до желаемого числа.
4. “Рюшечки”. При работе может использоваться только часть функционала приложения – какие-то таблицы могут быть пустыми. Причем количество таких таблиц может быть весьма большим. Возможно стоит их всех выделить в отдельную “ясельную” область. Можно также завести “карантинную” область для новых таблиц (т.е. тех, что только что появились в приложении), про которые непонятно как они будут себя вести. Присмотревшись к ним в течении некоторого времени, можно будет их переселить в более подходящее место. Возможно, стоит иметь под рукой “запасную” область на случай, если понадобится новая область, а базу останавливать нельзя. Впрочем, для этого можно использовать “ясельную” или “карантинную” области.

Для каждой области нужно задать своё RPB. Для небольших, можно принять равным 256. Либо определять более точно как RPB = DbBlockSize/MeanRecSize,
где MeanRecSize – средний размер записей по всем таблицам в данной области, но не как среднее значение средних размеров записей индивидуальных таблиц, которые приводятся в dbanalys`е. В качестве MeanRecSize в области стоит взять отношение общего размера всех записей таблиц в данной области к количеству этих записей.
Для больших областей настоятельно рекомендуется подбирать RPB исходя из реальных характеристик данных. Подробности в статье:
KB-P111065: FAQ - \'Best Practices\' For Managing Records-Per-Block Settings

Все, что было сказано выше, относилось к таблицам. Для каждой \"табличной\" области рекомендуется завести симметричную ей \"индексную\" область, в которой бы хранились все индексы всех таблиц, расположенных в данной \"табличной\" области.
Для области индексов значение RPB определим по умолчанию равным 1. RPB для индексных блоков имеет скорее символическое значение. В области с RPB 1 индексные блоки будут на 1-2% компактнее, так что это значение выбрано большей степенью для сигнализации – в этой области хранятся только индексы! (http://forum.infobit.ru/viewtopic.php?t=17 )

Количество и размеры томов областей.

Размер статического тома любой области принимается равным 1Gb. Количество томов в области прямо зависит от объема загружаемых в нее данных. Например, таблица Table4 имеет размер 7,2 Gb. Зная максимальный размер тома, мы получаем 7 статических томов плюс 1 динамический, итого 8 томов. В случае, если размер таблицы приближается к 1 Gb, как в таблице Table10, добавляется не один, а два тома – 1 статический и 1 динамический. Это связано с тем, чтобы заранее исключить необходимость добавление тома в ближайшем будущем.
Может возникнуть вопрос. Почему размер тома ограничивать одним гигабайтом? Почему не 2 Гб? А если Progress и файловая система поддерживают работу с файлами большого размера, то может, стоит дать им возможность расти больше 2 Гб? На производительность размер тома мало влияет. Более того, чем меньше файлов тем, вообще говоря, лучше для производительности. Делайте тома такого размера, как вам удобно, например, при копировании файлов.
Рекомендуемое чтение:
KB-P32184: Best database extent size
KB-P92875: Is there any performance impact when using database extent sizes more than 2GB?
Не стоит читать:
KB-19611: Extent size optimization under Unix
KB-16645: What is the optimum or recommended extent size for my OS?
Эти статьи устарели много лет назад.

Вернемся к нашему примеру.
Таким образом, мы получаем следующий структурный файл:
#
B <db>.b1
#
d \"Schema Area\":6,64 <db>.d1
#
d \"Table1 Area\":7,128 <db>_7.d1 f 1048576
d \"Table1 Area\":7,128 <db>_7.d2

#
d \"Table4 Area\":8,64 <db>_8.d1 f 1048576
d \"Table4 Area\":8,64 <db>_8.d2 f 1048576
d \"Table4 Area\":8,64 <db>_8.d3 f 1048576
d \"Table4 Area\":8,64 <db>_8.d4 f 1048576
d \"Table4 Area\":8,64 <db>_8.d5 f 1048576
d \"Table4 Area\":8,64 <db>_8.d6 f 1048576
d \"Table4 Area\":8,64 <db>_8.d7 f 1048576
d \"Table4 Area\":8,64 <db>_8.d8
#
d \"Table5 Area\":9,128 <db>_9.d1 f 1048576
d \"Table5 Area\":9,128 <db>_9.d2 f 1048576
d \"Table5 Area\":9,128 <db>_9.d3 f 1048576
d \"Table5 Area\":9,128 <db>_9.d4 f 1048576
d \"Table5 Area\":9,128 <db>_9.d5 f 1048576
d \"Table5 Area\":9,128 <db>_9.d6
#
d \"All Area\":10,128 <db>_10.d1 f 1048576
d \"All Area\":10,128 <db>_10.d2 f 1048576
d \"All Area\":10,128 <db>_10.d3 f 1048576
d \"All Area\":10,128 <db>_10.d4 f 1048576
d \"All Area\":10,128 <db>_10.d5 f 1048576
d \"All Area\":10,128 <db>_10.d6 f 1048576
d \"All Area\":10,128 <db>_10.d7
#
d \"Idx Area\":11,256 <db>_11.d1 f 1048576
d \"Idx Area\":11,256 <db>_11.d2
#
d \"Table10 Area\":12,128 <db>_12.d1 f 1048576
d \"Table10 Area\":12,128 <db>_12.d2
#
a <db>.a1
#
a <db>.a2
#
a <db>.a3
#
a <db>.a4
#
a <db>.a5
#
a <db>.a6
#
a <db>.a7
#
a <db>.a8
#
a <db>.a9
#
a <db>.a10

2. Dump данных

При выгрузке данных мы будем использовать двоичный dump. Общая процедура выгрузки разделяется на два этапа:
   Формирование скрипта выгрузки
   Запуск скрипта выгрузки

Формирование скрипта выгрузки.

Этот скрипт формируется следующей программой:

def var dbase as char init \"<полное>\".
def var dmpdir as char init \"<каталог>\".

output to value(\"<имя>\").
for each _file where _file-num > 0 no-lock.
output to value(\"<имя>\") append.
put unformatted \"_proutil \" + dbase + \" -C dump \" + _file-name + \" \" + dmpdir skip.
output close.
output to value(\"<имя>\") append.
put unformatted \"_proutil \" + dbase + \" -C load \" + dmpdir + _file-name + \".bd\" skip.
output close.
end.

Эта программа сформирует скрипт для dump`а примерно следующего содержания:

_proutil <db> -C dump <table1> /home/dump/
_proutil <db> -C dump <table2> /home/dump/
_proutil <db> -C dump <table3> /home/dump/

А также параллельно скрипт для load`а:
_proutil <db> -C load /home/dump/<table>.bd
_proutil <db> -C load /home/dump/<table>.bd
_proutil <db> -C load /home/dump/<table>.bd

Внимание: скрипт загрузки формируется по принципу одна таблица – одна запись в скрипте. Это верно для маленьких таблиц, не превышающих размер 2 Gb. Если таблица превышает размер в 2 Gb, то нужно самостоятельно добавить строки, что гарантирует полную загрузку таблицы, например, так:

_proutil <db> -C load /home/dump/<table>.bd
_proutil <db> -C load /home/dump/<table>.bd2
_proutil <db> -C load /home/dump/<table>.bd3
_proutil <db> -C load /home/dump/<table>.bdN

Связано это с тем, что progress не поддерживает файлы более 2Gb. Поэтому перед выгрузкой необходимо в Unix установить значение ulimit равное 1000000. Это позволит скрипту выгрузки (dump) переключаться на формирование следующего файла с записями, по достижении предела установленного в ulimit. После завершения выгрузки, нужно посмотреть какие таблицы выгружены в более чем один файл и добавить соответствующие строки в скрипт загрузки. (http://forum.infobit.ru/viewtopic.php?t=477&postdays=0&postorder=asc&start=15 (from George))
Для ускорения выгрузки можно запустить несколько процессов дампирования одновременно. Обычно рекомендуют 2-4 процесса на процессор. Мелкие таблицы сдампируются почти сразу. Останутся только несколько крупных \"игроков\". Если процессор и/или диски будут загружены на 100% - система работает с максимальной загрузкой.

К процедуре дампирования я бы добавил запуск dbanаlys\'а непосредствено пред дампом. Во-первых, будет возможность проверить, что во время \"переправы\" ни одна запись не утонула. Во-вторых, время работы dbanаlys\'а может служить оценкой скорости работы отчетов. Будет с чем сравнить после перезагрузки. Время старта и завершения dbanаlys\'а приводится в его логе. Если база уже разбита на области, то работу dbanаlys\'а можно ускорить, запустив его параллельно для каждой области. Это недокументированная возможность (просто забыли продокументировать). Синтаксис:
proutil <db> -C dbanalys \"<Area>\"

3. Dump метаданных

После формирования скриптов выгрузки и загрузки, необходимо сформировать df-файл всех таблиц БД, через Dump Data and Definitions редактора Progress. А также выгрузить данные по пользователям – таблица _user и значения сиквенсов – таблица _seqvals.

4. Backup существующей БД

Обязательно выполнить полную резервную копию базы, на случай восстановления БД, если в процессе разбиения на области, произойдут какие-либо ошибки.

5. Удаление существующей БД

После резервного копирования можно удалять базу данных, это выполняется утилитой prodel

prodel <OldDBname>

Предварительно сервер БД должен быть остановлен.

6. Создание новой БД

Поместите новый структурный файл в каталог, где будет находиться новая база данных, и запустите команду prostrct create:

prostrct create <newdbname> <имя> -blocksize 8192

В указанном каталоге будет создана новая структура БД. Примечание: данная структура еще не является рабочей БД, чтобы она стала пригодна для использования необходимо скопировать системные данные с эталонной базы.

Копирование БД с эталона, происходит следующей командой:

procopy /usr/dlc/empty <newdbname>

Загрузка метаданных

После копирования, база данных готова к работе. Теперь необходимо загрузить файл описаний таблиц (df), файл с данными пользователей и файл со значениями сиквенсов.

Внимание:
В связи с изменением структуры БД необходимо внести изменения в df-файл, заменив названия областей у таблиц и индексов, которые будут выделены. Предварительно сохраните копию df-файла.

Также, можно перенести необходимые таблицы в нужные области, уже после загрузки df-файла.

Перенести таблицу из одной области в другую можно следующей командой:
proutil <db> -C tablemove <table> <area>

Перенести индексы из одной области в другую можно так:
proutil <db> -C indexmove <index> <area>

Также, сейчас можно прогрузить df-файлы, содержащие новые индексы. Внимание: большое количество индексов, может привести к тому, что в момент переиндексации окажется недостаточным количество томов в области с индексами. Поэтому, предусмотрительно добавить в эту область как минимум еще два тома.

7. Load данных

Примечание: загрузка данных будет происходить быстрее, если база данных будет запущена в многопользовательском режиме в режиме no-integrity (-i).

Загрузка данных будет происходить по средствам скрипта загрузки. Можно разделить скрипт на несколько файлов с различным содержанием загружаемых таблиц, или разделить их по областям. После чего загружать параллельно - это позволит уменьшить время загрузки.
Внимание: не желательно при параллельной загрузке использовать одновременно и индексацию данных. Во всяком случае, у меня это привело к чрезмерному росту bi-файла и к останову БД. Быть может, этот процесс можно как-то контролировать, но я пока об этом не знаю. Также не стоит делать одновременную индексацию, если загружаются данные таблиц, &laquo;дамп-файлы&raquo; которых разделены (db, db2,bd3 и т.д.)
После загрузки записей (до перестройки индексов) снова запускаем dbanalys и проверяем, что в строке Итого число записей осталось тем же, что и перед выгрузкой.

8. Переиндексация БД

После завершения загрузки данных, таблицы в базе являются не индексированными, в результате чего, ни одна запись не доступна. Для этого необходимо сделать полную переиндексацию. Конечно же, можно было сформировать скрипт загрузки так чтобы записи сразу индексировались, но это не приемлемо когда загружаемая таблица разбита на несколько бинарных файлов, да и может привести к черезмерному росту bi - файла. Можно также исключить подобные таблицы из общей загрузки, а потом отдельно их проиндексировать. Но мы будет считать, что общая переиндексации наиболее выгодна для нас. Возможно, в будущем это может измениться. А пока, команда для полной переиндексации следующая:

proutil <db> -C idxbuild all -B 256 -TM 32 -TB 31 -SG 64 -SS <sort>

Подробнее о команде:

Параметры –TM и –TB увеличивают скорость сортировки. При перестройке индексов для временных файлов требуется 80-120% от объема наибольшей области. Параметр –TB как-то влияет объем временных файлов, но нелинейно и теория, стоящая за этим \"явлением\" мне не известна.
Весь объем временных файлов можно разместить либо в одной файловой системе (задается параметром -T), либо раскидать по разным файловым системам с помощью файла структуры каталогов сортировки (параметр -SS).
Progress создает несколько временных файлов, число которых зависит от значения параметра -SG.
Начиная с V9.1D09, временные файлы могут достигать размера больше 2 Гб, если файловая система поддерживает работу с большими файлами. Включать поддержку больших файлов для базы при этом необязательно.
Исключения:
1. SCO и Unixware, где Progress традиционно не поддерживает работу с большими файлами.
2. Linux V9.D09. На Linux\'е работа с большими файлами появилась в V9.1E
3. AIX. Причина - баг.

Если временные файлы не могут быть больше 2 Гб, а есть большие таблицы или области, то надо использовать многотомные временные файлы (-SS).
Файла структуры каталогов сортировки должен содержать полные пути к каждому каталогу, который будет задействован в процессе сортировки. В нашем случае, он имеет следующее содержание:
2000000 <path>/srt/srt1/
2000000 <path>/srt/srt2/
2000000 <path>/srt/srt3/
2000000 <path>/srt/srt4/
2000000 <path>/srt/srt5/
2000000 <path>/srt/srt6/
2000000 <path>/srt/srt7/
2000000 <path>/srt/srt8/
2000000 <path>/srt/srt9/
2000000 <path>/srt/srt10/
2000000 <path>/srt/srt11/
2000000 <path>/srt/srt12/
2000000 <path>/srt/srt13/
0 <path>/srt/srt14/

Последняя строка указывает на то, что заполнение этого каталога должно происходить пока есть свободное место на диске, в то время как использование места в предыдущих строках строго ограничено 2000000.
И если idxbuild все же использовал последний каталог, то надо расширить список каталогов с фиксированным размером.
Ограничение в 2000000 Кб (это меньше, чем 2 Гб). Больше максимальный размер файлов, меньше файлов потребуется создать. Количество временных файлов, открываемых утилитой idxbuild, в худшем случае может достигать -SG * <количество>. Плюс все экстенты базы данных. Плюс еще несколько файлов. Параметры ядра Unix\'а должны обеспечить возможность открыть такое количество файлов.
Поскольку сама утилита использует незначительный объем оперативной памяти, то перед запуском idxbuild можно создать memfs (файловая система, размещенная в памяти) и разместить здесь один том временных файлов. Это может ускорить работу примерно в 1.5 раза. Чем крупнее база и чем больше памяти можно отдать под memfs, тем заметнее будет эффект. По окончании работы idxbuild\'а эту файловую систему надо, конечно, удалить.
Кстати этот трюк можно использовать и при загрузки данных, временно разместив на memfs bi файл базы данных.
Также, если есть возможность, можно распределить srt-каталоги между различными дисковыми массивами.
Конечная черта в пути каталога сортировки обязательна.

9. Анализ созданной БД

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

Если ошибок не обнаружено, то разделение базы данных на области было успешно завершено.

Заключение

Материал подготовлен на основе дискуссии в форуме http://forum.infobit.ru/, и успешно опробован на реальных базах данных.

Башкатов В.Г 2006 г.






Главная |  Статьи |  Книги |  Гостевая |  Ссылки |  От автора |  Download ProKb


������ ᠩ� pr Online ProKB Blogger Welcome to Russian Progress Users Group at Facebook Welcome to Russian Progress Users Group at LinkedIn
© 2009 - 2011 Все права на материалы, находящиеся на сайте www.openedge.ru, охраняются в соответствии с законодательством РФ, в том числе, об авторском праве и смежных правах.
При любом использовании материалов сайта ссылка на источник обязательна.