Поле SQL Server ALTER NOT NULL занимает вечность - PullRequest
10 голосов
/ 20 июля 2009

Я хочу изменить поле из таблицы, в которой около 4 миллионов записей. Я гарантировал, что все значения этих полей НЕ ПУСТО (NULL), и хочу изменить это поле на NOT NULL

ALTER TABLE dbo.MyTable
ALTER COLUMN myColumn int NOT NULL

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

Также это может привести к блокировке таблицы?

Ответы [ 3 ]

4 голосов
/ 23 мая 2011

Единственный способ сделать это "быстро" (*), о котором я знаю, это

  • создание «теневой» таблицы с требуемым макетом
  • добавление триггера в исходную таблицу, чтобы любые операции вставки / обновления / удаления копировались в теневую таблицу (не забывайте, что любые NULL могут всплыть!)
  • скопировать все данные из источника в теневую таблицу, возможно, небольшими порциями (убедитесь, что вы можете обрабатывать уже скопированные данные с помощью триггера (ов), убедитесь, что данные поместятся в новую структуру (ISNULL ( ?)!)
  • вывести все зависимости из / в другие таблицы
  • когда все будет сделано, сделайте следующее внутри явной транзакции:
    • получить эксклюзивную блокировку таблицы на исходной таблице и одну на теневую таблицу
    • запустить сценарии для удаления зависимостей в таблицу-источник
    • переименовать исходную таблицу в другое (например, суффикс _old)
    • переименование теневой таблицы в исходное имя исходной таблицы
    • запустить сценарии, чтобы снова создать все зависимости

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

Как всегда, лучше всего сначала выполнить тестовый запуск на тестовом сервере =)

PS: пожалуйста, не поддавайтесь искушению воссоздать FK с помощью NOCHECK, это делает их бесполезными, поскольку оптимизатор не будет ни доверять им, ни учитывать их при построении плана запросов.

(*: где быстро сводится к: с наименьшим возможным временем простоя)

4 голосов
/ 20 июля 2009

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

CREATE TABLE Test
(
    T0 INT Not NULL,
    T1 INT NUll 
)

INSERT INTO Test VALUES(1, NULL) -- Works!

ALTER TABLE Test
    WITH NOCHECK
        ADD CONSTRAINT N_null_test CHECK (T1 IS NOT NULL)

    ALTER COLUMN T1 int NOT NULL 

INSERT INTO Test VALUES(1, NULL) -- Doesn't work now!

На самом деле у вас есть два варианта (добавлен третий, см. Редактирование):

  1. Используйте ограничение, которое предотвратит обновление любых новых строк и оставит исходные без изменений.
  2. Обновите строки, которые являются нулевыми, на что-то другое, а затем примените параметр не нулевого изменения. Это действительно должно быть выполнено в нерабочее время, если вы не возражаете против процессов, заблокированных за столом.

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

Это все, как говорится, если вы собираетесь использовать второй вариант, вы можете минимизировать объем работы, которую вы выполняете в нерабочее время. Поскольку перед изменением столбца необходимо убедиться, что строки обновлены до значения, не равного NULL, вы можете написать курсор медленно (относительно выполнения всего этого сразу)

  1. Пройти через каждый ряд
  2. Проверьте, является ли оно нулевым
  3. Обновите его соответствующим образом. Это займет некоторое время, но не заблокирует доступ всей таблицы к другим программам. (Не забудьте с (rowlock) табличной подсказкой!)

РЕДАКТИРОВАТЬ : Я просто подумал о третьем варианте: Вы можете создать новую таблицу с соответствующими столбцами, а затем экспортировать данные из исходной таблицы в новую. Когда это будет сделано, вы можете удалить исходную таблицу и изменить имя новой на старую. Для этого вам нужно будет отключить зависимости от оригинала и установить их обратно на новую, когда вы закончите, но этот процесс значительно сократит объем работы, которую вам придется выполнять в нерабочее время. Это тот же подход, который используется сервером sql при внесении изменений в порядок столбцов в таблицах через среду управления. Для этого подхода я бы сделал вставку по частям, чтобы убедиться, что вы не вызовете отмены нагрузки на систему и не позволите другим получить к ней доступ. Затем в нерабочее время вы можете удалить оригинал, переименовать вторую, применить зависимости и т. Д. У вас все равно останется работа в нерабочее время, но она будет незначительной по сравнению с другим подходом.

Ссылка на использование sp_rename .

2 голосов
/ 18 мая 2011

Извините за уныние, но:

  • Любые способы ускорить его: нет, если вы хотите изменить саму структуру таблицы
  • или я застрял, просто делая это ночью в нерабочее время? Да, и это, вероятно, к лучшему, как отметил @HLGEM
  • Также это может вызвать блокировку таблицы? Да

Не имеет прямого отношения к вам (потому что речь идет о переходе от NOT NULL к NULL), но интересно прочитать эту тему: http://beyondrelational.com/blogs/sankarreddy/archive/2011/04/05/is-alter-table-alter-column-not-null-to-null-always-expensive.aspx

И, наконец, некоторая древняя история - по эквивалентному вопросу на форуме в 2005 году было сделано то же самое предложение, что и @Kevin, предложенный выше, - используя ограничение вместо того, чтобы сделать сам столбец необнуляемым: http://www.sqlteam.com/Forums/topic.asp?TOPIC_ID=50671

...