обновление первичного ключа основных и дочерних таблиц для больших таблиц - PullRequest
0 голосов
/ 20 ноября 2008

У меня довольно большая база данных с мастер-таблицей с GUID с одним столбцом (алгоритм, подобный пользовательскому GUID) в качестве первичного ключа и 8 дочерних таблиц, которые имеют отношения внешнего ключа с этим столбцом GUID. Все таблицы имеют примерно 3-8 миллионов записей. Ни в одной из этих таблиц нет BLOB / CLOB / TEXT или каких-либо других необычных типов данных, кроме обычных чисел, переменных, дат и временных отметок (около 15–45 столбцов в каждой таблице). Нет разделов или других индексов, кроме первичного и внешнего ключей.

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

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

  1. добавить новый столбец ngu_id и заполнить новым gu_id; отключить ограничения; обновить дочерние таблицы с помощью ngu_id как gu_id; переименование ngu_id-> gu_id; повторно включить ограничения
  2. чтение одной основной записи и зависимых дочерних записей из дочерних таблиц; вставить в ту же таблицу с новым gu_id; удалить все записи со старыми gu_ids
  3. Отбрасывание ограничений; добавить триггер в основную таблицу, чтобы обновлялись все дочерние таблицы; начать обновление старых gu_id с новыми новыми gu_ids; повторно включить ограничения
  4. добавить триггер к основной таблице, чтобы обновлялись все дочерние таблицы; начать обновление старых gu_id с новыми новыми gu_ids
  5. создать новый столбец ngu_ids во всех основных и дочерних таблицах; создать ограничения внешнего ключа для столбцов ngu_id; добавить триггер обновления в основную таблицу для каскадного значения в дочерних таблицах; вставить новые значения gu_id в столбец ngu_id; удалить старые ограничения внешнего ключа, основанные на gu_id; удалите столбец gu_id и переименуйте ngu_id в gu_id; при необходимости воссоздать ограничения;
  6. использовать on update cascade, если доступно?

Мои вопросы:

  1. Есть ли лучший способ? (Не могу зарыться головой в песок, должен это сделать)
  2. Какой самый подходящий способ сделать это? (Я должен сделать это в Oracle, SQL-сервере и mysql4, поэтому приветствуются взломы, зависящие от поставщика)
  3. Каковы типичные точки отказа для такого упражнения и как их минимизировать?

Если вы до сих пор со мной, спасибо и надеюсь, что вы можете помочь:)

Ответы [ 4 ]

2 голосов
/ 20 ноября 2008

Ваши идеи должны работать. во-первых, наверное, так, как я бы использовал. Некоторые предостережения и вещи, о которых стоит подумать, делая это:
Не делайте этого, если у вас нет текущей резервной копии.
Я бы оставил оба значения в основной таблице. Таким образом, если вам когда-нибудь понадобится выяснить из какой-нибудь старой бумажной работы, какая запись вам нужна, вы можете сделать это. Выключите базу данных для обслуживания, пока вы делаете это, и переведите ее в однопользовательский режим. Самое последнее, что вам нужно, когда вы делаете что-то подобное, - это пользователь, пытающийся внести изменения, пока вы находитесь в среднем потоке. Конечно, первое действие после однопользовательского режима - это вышеупомянутая резервная копия. Вы, вероятно, должны запланировать время простоя на некоторое время, когда использование является самым легким. Сначала протестируйте на dev! Это также должно дать вам представление о том, как долго вам нужно будет закрывать производство. Кроме того, вы можете попробовать несколько методов, чтобы увидеть, какой из них самый быстрый.
Обязательно сообщите пользователям заранее, что база данных будет закрыта в запланированное время для обслуживания и когда они могут ожидать, что она снова станет доступной. Убедитесь, что время в порядке. Люди действительно злятся, когда планируют опоздать на ежеквартальные отчеты, а база данных недоступна, и они этого не знали.
Существует довольно большое количество записей, вы можете запускать обновления дочерних таблиц пакетами (одна из причин не использовать каскадные обновления). Это может быть быстрее, чем пытаться обновить 5 миллионов записей одним обновлением. Однако не пытайтесь обновлять одну запись за раз, иначе вы все еще будете здесь в следующем году, выполняя эту задачу.
Удалите индексы в поле GUID во всех таблицах и создайте заново после завершения работы. Это должно улучшить производительность изменения.

0 голосов
/ 22 ноября 2008

На самом деле, это зависит от вашей РСУБД.

Используя Oracle, самый простой выбор - сделать все ограничения внешнего ключа «отложенными» (проверка при фиксации), выполнить обновления в одной транзакции, а затем зафиксировать.

0 голосов
/ 22 ноября 2008

Трудно сказать, что такое «лучший» или «наиболее подходящий» подход, поскольку вы не описали, что вы ищете в решении. Например, должны ли таблицы быть доступны для запроса при переходе на новые идентификаторы? Они должны быть доступны для одновременной модификации? Важно ли завершить миграцию как можно быстрее? Важно ли минимизировать пространство, используемое для миграции?

Сказав это, я бы предпочел # 1, а не ваши другие идеи, если они все отвечали вашим требованиям.

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

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

Рассматривали ли вы возможность использования CREATE TABLE AS SELECT (CTAS) для заполнения новых таблиц новыми идентификаторами? Вы будете делать копию существующих таблиц, и для этого потребуется дополнительное пространство, однако, скорее всего, это будет быстрее, чем обновление существующих таблиц на месте. Идея состоит в том, чтобы: (i) использовать CTAS для создания новых таблиц с новыми идентификаторами вместо старых, (ii) создавать индексы и ограничения в зависимости от обстоятельств для новых таблиц, (iii) удалять старые таблицы, (iv) переименовывать новые таблицы со старыми именами.

0 голосов
/ 20 ноября 2008

Создать новую таблицу со старыми и новыми значениями pk в ней. Поместите уникальные ограничения в оба столбца, чтобы убедиться, что вы ничего не нарушили.

Отключить ограничения.

Запустите обновления для всех таблиц, чтобы изменить старое значение на новое.

Включите PK, затем включите FK.

...