Перенос данных на чистую базу (постановка)

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
(Альтернативный способ переноса данных на чистую базу)
(См. также)
 
(не показаны 16 промежуточных версий 2 участников)
Строка 1: Строка 1:
 
Принципы ускорения:
 
Принципы ускорения:
  
* последовательное неиндексированное чтение исходных данных
+
* начальное создание оперативной БД физическим копированием файла исходной (архивной) БД
* отключение индексов, триггеров, ключей, ограничений на конечной базе данных
+
* однопроходное последовательное неиндексированное чтение данных
* обработка множества идентификаторов в оперативной памяти
+
* отключение индексов, триггеров, ключей, ограничений для удаления устаревших записей на оперативной БД
* пересылка данных между базами внутри сервера
+
* обработка списка идентификаторов в оперативной памяти
  
Примем:
+
Пусть:
  
A -- исходная база данных.
+
* A -- исходная (архивная) база данных.
B -- конечная база данных.
+
* B -- оперативная база данных.
  
Перед началом процесса проверяем базу А:
+
Все таблицы мы подразделяем на:
 +
 
 +
* Таблицу gd_document. Обрабатывается последней в два прохода. Сначала шапки, затем позиции.
 +
* Главные таблицы БО (кроме gd_document). Только на главные таблицы могут налагаться условия переноса.
 +
* Таблицы, связанные 1-к-1 в реляционной модели. Данные из этих таблиц переносятся, только если переносится главная запись.
 +
* Детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов). Данные из этих таблиц переносятся, если переносится соответствующая мастер запись. Мы вычисляем такие таблицы по наличию поля masterkey или masterdockey.
 +
* Таблицы-связки для атрибутов типа множество. Связки переносятся только в том случае, если переносится запись из таблицы, которой принадлежит атрибут типа множество.
 +
* Прочие таблицы (без идентификатора ИД или со сложным первичным ключем). Переносятся всегда.
 +
* Таблица [[GD_RUID]] (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД). Из таблицы удаляются записи для ИД, которые не были перенесены.
 +
* Таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP). Данные переносятся всегда.
 +
 
 +
Списки таблиц упорядочиваем по возрастанию количества внешних ссылок на таблицу.
 +
 
 +
Подготовка исходной базы данных:
  
 
# отключенные внешние ключи должны быть включены
 
# отключенные внешние ключи должны быть включены
Строка 17: Строка 30:
 
# кэш не должен превышать 500 Мб
 
# кэш не должен превышать 500 Мб
 
# аудит должен быть отключен
 
# аудит должен быть отключен
 +
# пользователю рекомендуется провести бэкап-разбэкап исходной базы перед началом процесса.
  
Пользователю рекомендуется провести бэкап-разбэкап исходной базы перед началом процесса.
+
База В получается из базы А путем копирования и присвоения нового идентификатора базы данных.
  
База B создается из копии метаданных А. На время переноса данных отключается принудительная запись и размер кэша устанавливается не более 500 Мб. Подключение осуществляется в режиме с отключенными триггерами базы данных. Генератор идентификаторов базы B увеличивается на заданную дельту.
+
Пусть:
  
В базе B создаем структуры:
+
* M -- множество идентификаторов, требуемых в базе В по условиям целостности.
 +
* M2 -- множество идентификаторов записей, не удовлетворяющих условиям.
 +
* L -- список пар идентификаторов, где первый -- ИД записи, второй -- ИД ссылки одного из полей этой записи.
  
# для хранения структуры БД в части удаленных\отключенных объектов метаданных
+
Алгоритм обработки базы В:
# для хранения информации о записях с начальным сальдо
+
# для хранения лога изменения данных
+
# для хранения информации об исходной БД
+
  
Считываем и запоминаем структуру базы B. Деактивируем или удаляем следующие объекты метаданных: триггеры, индексы, чеки, внешние ключи, первичные ключи, вычисляемые поля.
+
# Последовательно сканируем каждую таблицу в соответствии с ее типом (см. выше). Проверяем каждую запись.
 +
## Если запись удовлетворяет условию, то ее идентификатор и идентификаторы всех ссылок из нее заносим в М. При этом, если идентификатор ссылки находится в М2, то исключаем его оттуда и заносим в М все идентификаторы ссылок для данного идентификатора записи из списка L. После чего удаляем ненужные пары из L.
 +
## Если запись не удовлетворяет условию, то ее идентификатор заносим в М2, а в L заносим пары идентификатор записи - идентификатор ссылки, для всех ссылок, которых нет в М.
 +
# Таблицу gd_document обрабатываем в два прохода:  
 +
## сначала только шапки, аналогично общему алгоритму обработки записей.
 +
## затем только позиции. В М добавляем ИД позиции только в том случае, если там присутствует ИД шапки.
 +
# Деактивируем триггеры, удаляем индексы, удаляем внешние ключи, ограничения уникальности, первичные ключи.
 +
# Из всех таблиц удаляем записи, которых нет в М.
 +
# Восстанавливаем первичные ключи, ограничения уникальности, внешние ключи, индексы. Активируем триггеры.
  
Создаем множество R для идентификаторов объектов, подлежащих переносу из А в B.
+
=== Замечания по реализации ===
  
Выводим сальдовые значения и помещаем их в B. Помещаем в R идентификаторы объектов, необходимых для суммарных значений.
+
# Системные записи (ИД менее 147 000 000) и ссылки на системные записи игнорируем полностью.
 
+
# Подключение к базе В выполняем с отключенной сборкой мусора.
Все таблицы мы подразделяем на:
+
# Отключаем принудительную запись на базе В.
 
+
# М и М2 -- битовые массивы, изначальные размеры которым устанавливаем исходя из диапазона идентификаторов, вычисленного как [[GD_G_UNIQUE]] - 147000000.Используем класс TgsHugeIntSet.
* таблицу gd_document
+
* главные таблицы БО (кроме gd_document)
+
* таблицы, связанные 1-к-1 в реляционной модели
+
* детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов)
+
* таблицы-связки для атрибутов типа множество
+
* прочие таблицы (без идентификатора ИД или со сложным первичным ключем)
+
* таблица [[GD_RUID]] (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД)
+
* таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP)
+
 
+
Списки таблиц упорядочиваем по возрастанию количества внешних ссылок на таблицу.
+
 
+
Алгоритм переноса:
+
 
+
# Проходимся по таблицам-связкам для множеств и помещаем в R все встреченные идентификаторы элементов множеств.
+
# Организуем цикл по прочим таблицам. Для каждой сканируем все записи и добавляем все встреченные ссылки в R.
+
# Сканируем шапки из таблицы gd_document. Проверям на условия переноса. Если условия выполнены и ИД записи еще нет в R то:
+
## сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
+
## добавляем ее идентификатор в R.
+
# Сканируем позиции из таблицы gd_document. Если ИД записи еще нет в R и ИД шапки находится в R, то:
+
## сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы. 
+
## добавляем ее идентификатор в R.
+
# Организуем цикл по главным таблицам БО. Внутри каждой таблицы организуем цикл по всем записям. Если ИД записи не в R и по условиям она подлегает переносу, то:
+
## сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
+
## добавляем ее идентификатор в R.
+
# Организуем цикл по детальным таблицам и по таблицам 1-к-1. Если ИД главной записи находится в R, то: 
+
## сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
+
## добавляем ее идентификатор в R.
+
# Если в процессе выполнения пунктов 3-6 в R добавлен хотя бы один новый идентификатор, то повторяем цикл начиная с шага 3.
+
# Переносим данные из А в B:
+
## все данные прочих таблиц
+
## для таблиц с идентификаторами -- все записи, которые зафиксированы в R
+
## для таблиц-связок -- все записи, относящиеся к объектам из R 
+
 
+
Примечание: при выполнении шагов 5 и 6, если таблица имеет древовидную структуру, то организуется цикл от первой до последней записи, который повторяется пока в процессе обработки не было добавлено ни одного нового ИД в R.
+
 
+
Восстанавливаем в B удаленные и деактивированные объекты метаданных.
+
 
+
В базе B на каждую таблицу создаются триггеры после изменения и после удаления, которые синхронизируют изменения с базой А. (или фиксируют изменения для последующей синхронизации).
+
 
+
Создаем в А таблицу и записываем параметры базы B.
+
  
 
==== Работа с базой А после разделения ====
 
==== Работа с базой А после разделения ====
Строка 88: Строка 69:
  
 
Сначала выполняются все отложенные операции синхронизации изменений в B.
 
Сначала выполняются все отложенные операции синхронизации изменений в B.
 
Создается база C, как копия метаданных базы B. Запоминается ее структура. Отключаются индексы, чеки, триггеры, ключи. Переносится на нее информация из A и из B. Не переносятся суммарные данные. Восстанавливаются ключи, индексы, триггеры, чеки.
 
  
 
В общем случае потребуется на базу А накатить все настройки, которые были установлены на B с момента разъединения этих баз.
 
В общем случае потребуется на базу А накатить все настройки, которые были установлены на B с момента разъединения этих баз.
  
=== Альтернативный способ переноса данных на чистую базу  ===
+
===См. также===
  
# Базу В делаем из базы А с помощью утилиты nbackup. В начальном состоянии -- это точная копия базы А.
+
* [[Полное закрытие периода (постановка)]]
# Определяем зависимости на базе А.
+
## Все таблицы подразделяем на:
+
### Таблицы с целочисленным первичным ключем (без разницы, это главная таблица БО или присоединенная 1-к-1)  
+
### Таблицы-связки для множеств
+
### Прочие таблицы (без ключа, с нецелочисленным ключем, со сложным ключем)
+
## Для хранения зависимостей нам понадобятся структуры:
+
### Массив M ссылок на блоки памяти. Номер ячейки в массиве соответствует идентификатору. Содержимое ячейки -- это номер блока со ссылками.
+
### Массив S блоков ссылок. Каждый блок имеет размер 16 байт и содержит в себе три ссылки и номер следующего блока в цепочке.
+
## Организуем цикл по всем таблицам в БД
+
### Прочие таблицы пропускаем.
+
### Таблицы с целочисленным ключем обрабатываем следующим образом:
+
#### Проверяем ячейку с номером, равным идентификатору, в М. Если она пуста, то берем очередной свободный блок в S и его номер заносим в ячейку. Блок заполняем ссылками из рассматриваемой записи. Если ссылки не умещаются в один блок, то берем следующий. В каждом предыдущем блоке хранится номер следующего в цепочке. При этом, не заносим дважды повторяющиеся ключи.
+
#### Если ячейка не пуста, то берем из нее номер первого блока в цепочке и считываем все идентификаторы (они понадобятся нам, чтобы избежать дублирования). Дописываем в цепочку блоков идентификаторы из рассматриваемой записи. При необходимости выделяем новые блоки и добавляем их в цепочку.
+
### Таблицы-связки обрабатываем следующим образом: заносим в цепочку идентификатор элемента множества для объекта, которому принадлежит данный атрибут типа множество.
+
# Удаляем ключи, индексы, деактивируем триггеры.
+
  
 +
[[Category:Постановка-Сделано]]
 +
[[Category:Репликация]]
  
[[Category:Постановка]]
+
__NOTOC__

Текущая версия на 14:49, 2 апреля 2014

Принципы ускорения:

  • начальное создание оперативной БД физическим копированием файла исходной (архивной) БД
  • однопроходное последовательное неиндексированное чтение данных
  • отключение индексов, триггеров, ключей, ограничений для удаления устаревших записей на оперативной БД
  • обработка списка идентификаторов в оперативной памяти

Пусть:

  • A -- исходная (архивная) база данных.
  • B -- оперативная база данных.

Все таблицы мы подразделяем на:

  • Таблицу gd_document. Обрабатывается последней в два прохода. Сначала шапки, затем позиции.
  • Главные таблицы БО (кроме gd_document). Только на главные таблицы могут налагаться условия переноса.
  • Таблицы, связанные 1-к-1 в реляционной модели. Данные из этих таблиц переносятся, только если переносится главная запись.
  • Детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов). Данные из этих таблиц переносятся, если переносится соответствующая мастер запись. Мы вычисляем такие таблицы по наличию поля masterkey или masterdockey.
  • Таблицы-связки для атрибутов типа множество. Связки переносятся только в том случае, если переносится запись из таблицы, которой принадлежит атрибут типа множество.
  • Прочие таблицы (без идентификатора ИД или со сложным первичным ключем). Переносятся всегда.
  • Таблица GD_RUID (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД). Из таблицы удаляются записи для ИД, которые не были перенесены.
  • Таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP). Данные переносятся всегда.

Списки таблиц упорядочиваем по возрастанию количества внешних ссылок на таблицу.

Подготовка исходной базы данных:

  1. отключенные внешние ключи должны быть включены
  2. блокировка периода должна быть снята
  3. кэш не должен превышать 500 Мб
  4. аудит должен быть отключен
  5. пользователю рекомендуется провести бэкап-разбэкап исходной базы перед началом процесса.

База В получается из базы А путем копирования и присвоения нового идентификатора базы данных.

Пусть:

  • M -- множество идентификаторов, требуемых в базе В по условиям целостности.
  • M2 -- множество идентификаторов записей, не удовлетворяющих условиям.
  • L -- список пар идентификаторов, где первый -- ИД записи, второй -- ИД ссылки одного из полей этой записи.

Алгоритм обработки базы В:

  1. Последовательно сканируем каждую таблицу в соответствии с ее типом (см. выше). Проверяем каждую запись.
    1. Если запись удовлетворяет условию, то ее идентификатор и идентификаторы всех ссылок из нее заносим в М. При этом, если идентификатор ссылки находится в М2, то исключаем его оттуда и заносим в М все идентификаторы ссылок для данного идентификатора записи из списка L. После чего удаляем ненужные пары из L.
    2. Если запись не удовлетворяет условию, то ее идентификатор заносим в М2, а в L заносим пары идентификатор записи - идентификатор ссылки, для всех ссылок, которых нет в М.
  2. Таблицу gd_document обрабатываем в два прохода:
    1. сначала только шапки, аналогично общему алгоритму обработки записей.
    2. затем только позиции. В М добавляем ИД позиции только в том случае, если там присутствует ИД шапки.
  3. Деактивируем триггеры, удаляем индексы, удаляем внешние ключи, ограничения уникальности, первичные ключи.
  4. Из всех таблиц удаляем записи, которых нет в М.
  5. Восстанавливаем первичные ключи, ограничения уникальности, внешние ключи, индексы. Активируем триггеры.

[править] Замечания по реализации

  1. Системные записи (ИД менее 147 000 000) и ссылки на системные записи игнорируем полностью.
  2. Подключение к базе В выполняем с отключенной сборкой мусора.
  3. Отключаем принудительную запись на базе В.
  4. М и М2 -- битовые массивы, изначальные размеры которым устанавливаем исходя из диапазона идентификаторов, вычисленного как GD_G_UNIQUE - 147000000.Используем класс TgsHugeIntSet.

[править] Работа с базой А после разделения

IDA -- значение генератора из БД А на момент старта процесса. IDB = IDA + 1000000 -- значение генератора в БД B, устанавливаемое на момент окончания процесса.

В базе А создается триггер на коммит транзакции, который проверяет, если значение генератора больше, чем IDB - 1000, то выдается исключение.

[править] Слияние баз А и B

Сначала выполняются все отложенные операции синхронизации изменений в B.

В общем случае потребуется на базу А накатить все настройки, которые были установлены на B с момента разъединения этих баз.

[править] См. также

Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты