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

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
Строка 1: Строка 1:
 
Принципы ускорения:
 
Принципы ускорения:
  
* последовательное неиндексированное чтение исходных данных
+
* начальное создание оперативной БД физическим копированием файла исходной (архивной) БД
* отключение индексов, триггеров, ключей, ограничений на конечной базе данных
+
* однопроходное последовательное неиндексированное чтение данных
* обработка множества идентификаторов в оперативной памяти
+
* отключение индексов, триггеров, ключей, ограничений для удаления устаревших записей на оперативной БД
 +
* обработка списка идентификаторов в оперативной памяти
  
 
Пусть:
 
Пусть:
  
* A -- исходная база данных.
+
* A -- исходная (архивная) база данных.
* B -- конечная база данных.
+
* B -- оперативная база данных.
 +
 
 +
Все таблицы мы подразделяем на:
 +
 
 +
* таблицу gd_document
 +
* главные таблицы БО (кроме gd_document)
 +
* таблицы, связанные 1-к-1 в реляционной модели
 +
* детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов)
 +
* таблицы-связки для атрибутов типа множество
 +
* прочие таблицы (без идентификатора ИД или со сложным первичным ключем)
 +
* таблица [[GD_RUID]] (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД)
 +
* таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP)
 +
 
 +
Списки таблиц упорядочиваем по возрастанию количества внешних ссылок на таблицу.
 +
 
 +
Подготовка исходной базы данных:
 +
 
 +
# отключенные внешние ключи должны быть включены
 +
# блокировка периода должна быть снята
 +
# кэш не должен превышать 500 Мб
 +
# аудит должен быть отключен
 +
# пользователю рекомендуется провести бэкап-разбэкап исходной базы перед началом процесса.
 +
 
 +
База В получается из базы А путем копирования и присвоения нового идентификатора базы данных.
 +
 
 +
= Черновик =
 +
 
 +
 
 
* T -- множество всех таблиц в базе данных.
 
* T -- множество всех таблиц в базе данных.
 
* T<sup>'</sup> -- множество таблиц, целиком переносимых на конечную БД.
 
* T<sup>'</sup> -- множество таблиц, целиком переносимых на конечную БД.
Строка 22: Строка 50:
 
Алгоритм усечения базы В построим следующим образом:
 
Алгоритм усечения базы В построим следующим образом:
  
# Перед началом процесса проверяем базу А:
+
 
## отключенные внешние ключи должны быть включены
+
 
## блокировка периода должна быть снята
+
## кэш не должен превышать 500 Мб
+
## аудит должен быть отключен
+
## Пользователю рекомендуется провести бэкап-разбэкап исходной базы перед началом процесса.
+
# База В получается из базы А путем копирования и присвоения нового идентификатора базы данных.
+
 
# Удаляем из базы В все индексы, первичные ключи, внешние ключи. Деактивируем все триггеры.
 
# Удаляем из базы В все индексы, первичные ключи, внешние ключи. Деактивируем все триггеры.
 
# Обрабатываем таблицы из T<sup>'</sup>. Сканируем каждую запись:
 
# Обрабатываем таблицы из T<sup>'</sup>. Сканируем каждую запись:
Строка 79: Строка 102:
 
Выводим сальдовые значения и помещаем их в B. Помещаем в R идентификаторы объектов, необходимых для суммарных значений.
 
Выводим сальдовые значения и помещаем их в B. Помещаем в R идентификаторы объектов, необходимых для суммарных значений.
  
Все таблицы мы подразделяем на:
 
  
* таблицу gd_document
 
* главные таблицы БО (кроме gd_document)
 
* таблицы, связанные 1-к-1 в реляционной модели
 
* детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов)
 
* таблицы-связки для атрибутов типа множество
 
* прочие таблицы (без идентификатора ИД или со сложным первичным ключем)
 
* таблица [[GD_RUID]] (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД)
 
* таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP)
 
 
Списки таблиц упорядочиваем по возрастанию количества внешних ссылок на таблицу.
 
  
 
Алгоритм переноса:
 
Алгоритм переноса:

Версия 12:00, 23 февраля 2012

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

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

Пусть:

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

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

  • таблицу gd_document
  • главные таблицы БО (кроме gd_document)
  • таблицы, связанные 1-к-1 в реляционной модели
  • детальные таблицы (таблицы с дополнительной информацией, таблицы с позициями документов, таблицы документов)
  • таблицы-связки для атрибутов типа множество
  • прочие таблицы (без идентификатора ИД или со сложным первичным ключем)
  • таблица GD_RUID (id в этой таблице будет обязательно дублироваться с одним из id из другой таблицы в БД)
  • таблицы, которые используют свои генераторы для присвоения идентификаторов (например, GD_USERGROUP)

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

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

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

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

Черновик

  • T -- множество всех таблиц в базе данных.
  • T' -- множество таблиц, целиком переносимых на конечную БД.
  • T'' -- множество главных таблиц БО, частично переносимых на конечную БД.
  • M -- множество идентификаторов, требуемых в базе В по условиям целостности.
  • М' -- множество идентификаторов, подлежащих удалению из В.
  • М'' -- множество идентификаторов, подлежащих перепроверке.

Выполняется условие:

T = T' U T''

Алгоритм усечения базы В построим следующим образом:


  1. Удаляем из базы В все индексы, первичные ключи, внешние ключи. Деактивируем все триггеры.
  2. Обрабатываем таблицы из T'. Сканируем каждую запись:
    1. Заносим ИД в М.
    2. Заносим все ссылки на таблицы из T'' и T''' в М.
  3. Обрабатываем таблицы из T''.Сканируем каждую запись:
    1. Если ИД в М, то заносим все ссылки на таблицы из T'' и T''' в М.
    2. Если ИД не в М, то проверяем на условие переноса. Если запись подлежит переносу, то заносим в М ИД и все ссылки на таблицы из T''.
    3. Если запись подлежит удалению, то заносим ее ИД в М'.
    4. При этом, перед занесением ссылки в М проверяем ее наличие в М'. Если она присутствует там, то помещаем ее в М'' и в М.
  4. Обрабатываем таблицы из T'''. Сканируем каждую запись:
    1. Если ИД в М, то заносим все ссылки на таблицы из T'' в М.
    2. При этом, перед занесением ссылки в М проверяем ее наличие в М'. Если она присутствует там, то помещаем ее в М'' и в М.
  5. Обрабатываем все ИД из М'' по алгоритму для таблиц из T'''. Данный пункт повторяем, пока М'' не станет пустым множеством.
  6. Восстанавливаем на В удаленные ограничения, индексы и триггеры, руководствуясь информацией из А.

Специфика обработки отдельных видов таблиц

gd_document

Если на таблицу наложены условия, то она обрабатывается последней из всех таблиц T''.

gd_ruid

Таблица не участвует в общем алгоритме. По окончании процесса, удаляем из нее записи с ИД из М'.

Замечания по реализации

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

Устаревшее

База B создается из копии метаданных А. На время переноса данных отключается принудительная запись и размер кэша устанавливается не более 500 Мб. Подключение осуществляется в режиме с отключенными триггерами базы данных. Генератор идентификаторов базы B увеличивается на заданную дельту.

В базе B создаем структуры:

  1. для хранения структуры БД в части удаленных\отключенных объектов метаданных
  2. для хранения информации о записях с начальным сальдо
  3. для хранения лога изменения данных
  4. для хранения информации об исходной БД

Считываем и запоминаем структуру базы B. Деактивируем или удаляем следующие объекты метаданных: триггеры, индексы, чеки, внешние ключи, первичные ключи, вычисляемые поля.

Создаем множество R для идентификаторов объектов, подлежащих переносу из А в B.

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


Алгоритм переноса:

  1. Проходимся по таблицам-связкам для множеств и помещаем в R все встреченные идентификаторы элементов множеств.
  2. Организуем цикл по прочим таблицам. Для каждой сканируем все записи и добавляем все встреченные ссылки в R.
  3. Сканируем шапки из таблицы gd_document. Проверям на условия переноса. Если условия выполнены и ИД записи еще нет в R то:
    1. сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
    2. добавляем ее идентификатор в R.
  4. Сканируем позиции из таблицы gd_document. Если ИД записи еще нет в R и ИД шапки находится в R, то:
    1. сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
    2. добавляем ее идентификатор в R.
  5. Организуем цикл по главным таблицам БО. Внутри каждой таблицы организуем цикл по всем записям. Если ИД записи не в R и по условиям она подлегает переносу, то:
    1. сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
    2. добавляем ее идентификатор в R.
  6. Организуем цикл по детальным таблицам и по таблицам 1-к-1. Если ИД главной записи находится в R, то:
    1. сканируем все поля-ссылки в этой записи и добавляем в R идентификаторы.
    2. добавляем ее идентификатор в R.
  7. Если в процессе выполнения пунктов 3-6 в R добавлен хотя бы один новый идентификатор, то повторяем цикл начиная с шага 3.
  8. Переносим данные из А в B:
    1. все данные прочих таблиц
    2. для таблиц с идентификаторами -- все записи, которые зафиксированы в R
    3. для таблиц-связок -- все записи, относящиеся к объектам из R

Примечание: при выполнении шагов 5 и 6, если таблица имеет древовидную структуру, то организуется цикл от первой до последней записи, который повторяется пока в процессе обработки не было добавлено ни одного нового ИД в R.

Восстанавливаем в B удаленные и деактивированные объекты метаданных.

В базе B на каждую таблицу создаются триггеры после изменения и после удаления, которые синхронизируют изменения с базой А. (или фиксируют изменения для последующей синхронизации).

Создаем в А таблицу и записываем параметры базы B.

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

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

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

Слияние баз А и B

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

Создается база C, как копия метаданных базы B. Запоминается ее структура. Отключаются индексы, чеки, триггеры, ключи. Переносится на нее информация из A и из B. Не переносятся суммарные данные. Восстанавливаются ключи, индексы, триггеры, чеки.

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

Альтернативный способ переноса данных на чистую базу

  1. Базу В делаем из базы А с помощью утилиты nbackup. В начальном состоянии -- это точная копия базы А.
  2. Определяем зависимости на базе А.
    1. Все таблицы подразделяем на:
      1. Таблицы с целочисленным первичным ключем (без разницы, это главная таблица БО или присоединенная 1-к-1)
      2. Таблицы-связки для множеств
      3. Прочие таблицы (без ключа, с нецелочисленным ключем, со сложным ключем)
    2. Для хранения зависимостей нам понадобятся структуры:
      1. Массив M ссылок на блоки памяти. Номер ячейки в массиве соответствует идентификатору. Содержимое ячейки -- это номер блока со ссылками.
      2. Массив S блоков ссылок. Каждый блок имеет размер 16 байт и содержит в себе три ссылки и номер следующего блока в цепочке.
    3. Организуем цикл по всем таблицам в БД
      1. Прочие таблицы пропускаем.
      2. Таблицы с целочисленным ключем обрабатываем следующим образом:
        1. Проверяем ячейку с номером, равным идентификатору, в М. Если она пуста, то берем очередной свободный блок в S и его номер заносим в ячейку. Блок заполняем ссылками из рассматриваемой записи. Если ссылки не умещаются в один блок, то берем следующий. В каждом предыдущем блоке хранится номер следующего в цепочке. При этом, не заносим дважды повторяющиеся ключи.
        2. Если ячейка не пуста, то берем из нее номер первого блока в цепочке и считываем все идентификаторы (они понадобятся нам, чтобы избежать дублирования). Дописываем в цепочку блоков идентификаторы из рассматриваемой записи. При необходимости выделяем новые блоки и добавляем их в цепочку.
      3. Таблицы-связки обрабатываем следующим образом: заносим в цепочку идентификатор элемента множества для объекта, которому принадлежит данный атрибут типа множество.
  3. Удаляем ключи, индексы, деактивируем триггеры.
Персональные инструменты
Пространства имён

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