Как обновить ссылки на идентификаторы guid при конвертации в идентификаторы идентификаторов - PullRequest
0 голосов
/ 24 июня 2010

Я пытаюсь преобразовать таблицы из первичных ключей / кластерных индексов guid в int. Это для SQL Server 2005. Есть две таблицы MainTable и RelatedTable, и текущая структура таблицы выглядит следующим образом:

MainTable [40 миллионов строк]

IDGuid - uniqueidentifier - PK
-- [data columns]

RelatedTable [400 миллионов строк]

RelatedTableID - uniqueidentifier - PK
MainTableIDGuid - uniqueidentifier [foreign key to MainTable]
SequenceNumber - int - incrementing number per main table entry since there can be multiple entries related to a given row in the main table. These go from 1,2,3... etc for each MainTableIDGuid value.
-- [data columns]

Кластерный индекс для MainTable в настоящее время является первичным ключом (IDGuid). Кластерный индекс для RelatedTable в настоящее время (MainTableIDGuid, SequenceNumber).

Я хочу, чтобы мое обращение сделало несколько вещей: <</p>

  1. Измените MainTable на использование целочисленного идентификатора вместо GUID
  2. Добавить столбец MainTableIDInt в связанную таблицу, которая ссылается на целочисленный идентификатор основной таблицы
  3. Измените первичный ключ и кластерный индекс с RelatedTable на (MainTableIDInt, SequenceNumber)
  4. Избавьтесь от направляющих столбцов.

Я написал скрипт для следующего:

  1. Добавить столбец IDInt int IDENTITY к MainTable. Это делает перестройку таблицы и генерирует новые значения идентификатора идентификатора.
  2. Добавить столбец MainTableIDInt int к RelatedTable.

Следующим шагом является заполнение столбца RelatedTable.MainTableIDInt для каждой строки соответствующим значением MainTable.IDInt [на основе соответствующих идентификаторов guid]. Это шаг, который я одержим. Я понимаю, что это не будет быстрым, но я бы хотел, чтобы он работал как можно лучше.

Я могу написать инструкцию SQL, которая делает это обновление:

UPDATE RelatedTable
SET RelatedTable.MainTableIDInt = (SELECT MainTable.IDInt FROM MainTable WHERE MainTable.IDGuid = RelatedTable.MainTableIDGuid)

или

UPDATE RelatedTable
SET RelatedTable.MainTableIDInt = MainTable.IDInt
FROM RelatedTable 
LEFT OUTER JOIN MainTable ON RelatedTable.MainTableIDGuid = MainTable.IDGuid

«Показать примерный план выполнения» отображается примерно одинаково для обоих этих запросов. План выполнения, который он выкладывает, выполняет следующие действия:

  1. Кластерный индекс просматривает MainTable и RelatedTable и выполняет слияние с ними [приблизительное число строк = 400 миллионов]
  2. Сортировка [оценочное количество строк = 400 миллионов]
  3. Обновление кластеризованного индекса в течение RelatedTable [расчетное число строк = 400 миллионов]

Я обеспокоен производительностью этого [сортировка 400 миллионов строк звучит неприятно]. Оправданы ли мои опасения по поводу выполнения этого плана выполнения? Есть ли лучший способ обновить новый идентификатор для моей связанной таблицы, который будет масштабироваться с учетом размера таблиц?

1 Ответ

1 голос
/ 24 июня 2010

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

Update ChildTable
Set NewIntForeignKeyId = P.NewIntPrimaryKey
From ChildTable As C
    Join ParentTable As P
        On P.PrimaryKey = C.ForeignKey

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

Как только у вас есть данные, я бы отбросил все первичные ограничения, ограничения уникальности, ограничения внешнего ключа и уникальные индексы.Отбросьте кластерный индекс / ограничение последним.Затем я бы добавил кластеризованные индексы ко всем таблицам, а после этого воссоздал бы уникальные ограничения, ограничения внешнего ключа и индексы.Если вы не удалите существующие индексы до воссоздания кластерного индекса, он будет перестраивать существующие индексы дважды: один раз, когда вы отбрасываете кластерный индекс, и снова, когда вы воссоздаете его.

Кстати, я очень сомневаюсь, что естьспособ избежать сканирования таблицы для такого рода вещей, так как вы собираетесь обновлять каждую строку.

...