Как Вы добавляете Столбец NOT NULL к большой таблице в SQL Server?

50
задан longda 10 March 2014 в 10:25
поделиться

8 ответов

Я столкнулся с этой проблемой и в своей работе. И мое решение соответствует пункту 2.

Вот мои шаги (я использую SQL Server 2005):

1) Добавить столбец в таблицу со значением по умолчанию:

ALTER TABLE MyTable ADD MyColumn varchar(40) DEFAULT('')

2) Добавить NOT NULL ограничение с параметром NOCHECK . NOCHECK не применяет к существующим значениям:

ALTER TABLE MyTable WITH NOCHECK
ADD CONSTRAINT MyColumn_NOTNULL CHECK (MyColumn IS NOT NULL)

3) Постепенно обновлять значения в таблице:

GO
UPDATE TOP(3000) MyTable SET MyColumn = '' WHERE MyColumn IS NULL
GO 1000
  • Оператор обновления обновляет только максимум 3000 записей. Это позволяет одновременно сохранять фрагмент данных. Я должен использовать «MyColumn IS NULL», потому что моя таблица не имеет первичного ключа последовательности.

  • GO 1000 выполнит предыдущий оператор 1000 раз. Это обновит 3 миллиона записей, если вам нужно больше, просто увеличьте это число. Он будет выполняться до тех пор, пока SQL Server не вернет 0 записей для оператора UPDATE.

59
ответ дан 7 November 2019 в 11:05
поделиться

Вот то, что я попробовал бы:

  • Делают полное резервное копирование базы данных.
  • Добавляют новый столбец, разрешение аннулирует - не устанавливают значение по умолчанию.
  • Набор ПРОСТОЕ восстановление, которое усекает журнал tran, как только каждый пакет фиксируется.
  • SQL: ALTER DATABASE XXX ВОССТАНОВЛЕНИЙ НАБОРА, ПРОСТЫХ
  • Выполнение обновление в пакетах, поскольку, Вы обсудили выше, фиксируя после каждого.
  • Сброс новый столбец, чтобы больше не позволить аннулирует.
  • Возвращаются к нормальному ПОЛНОМУ восстановлению.
  • SQL: ALTER DATABASE XXX ВОССТАНОВЛЕНИЙ НАБОРА, ПОЛНЫХ
  • Резервное копирование база данных снова.

использование ПРОСТОЙ модели восстановления не прекращает регистрироваться, но это значительно уменьшает свое влияние. Это вызвано тем, что сервер отбрасывает информацию о восстановлении после каждой фиксации.

3
ответ дан RoadWarrior 7 November 2019 в 11:05
поделиться

Вы могли:

  1. Запускают транзакцию.
  2. Захват запись соединяет Вашу исходную таблицу, таким образом, никто не пишет в него.
  3. Составляют теневую таблицу с новой схемой.
  4. Передают все данные от исходной таблицы.
  5. выполняются sp_rename для переименования старой таблицы.
  6. выполняются sp_rename для переименования новой таблицы в.
  7. Наконец, Вы фиксируете транзакцию.

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

2
ответ дан Sam Saffron 7 November 2019 в 11:05
поделиться

Я думаю, что это зависит от разновидности SQL, которую Вы используете, но что, если Вы взяли опцию 2, но в самом конце, изменяют таблицу таблицы к не пустой со значением по умолчанию?

это было бы быстро, так как это видит, что все значения не являются пустыми?

0
ответ дан Pyrolistical 7 November 2019 в 11:05
поделиться

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

, Если Вы действительно не заботитесь, находится ли столбец в таблице, то я предполагаю, сегментированный подход является следующим лучше всего. Хотя, я действительно стараюсь избегать этого (до такой степени, что я не делаю этого), потому что тогда как Charles Bretana говорит, необходимо будет удостовериться и найти все места, которые обновляют/вставляют ту таблицу и изменяют тех. Тьфу!

0
ответ дан Nick DeVore 7 November 2019 в 11:05
поделиться

Я имел подобную проблему и пошел для Вашей опции № 2. Это берет 20 минутам этот путь, в противоположность 32 часам другой путь!!! Огромная разница, спасибо за подсказку. Я записал полную запись в блоге об этом, но здесь являюсь важным sql:

Alter table MyTable
Add MyNewColumn char(10) null default '?';
go

update MyTable set MyNewColumn='?' where MyPrimaryKey between 0 and 1000000
go
update MyTable set MyNewColumn='?' where MyPrimaryKey between 1000000 and 2000000
go
update MyTable set MyNewColumn='?' where MyPrimaryKey between 2000000 and 3000000
go
..etc..

Alter table MyTable
Alter column MyNewColumn char(10) not null;

И запись в блоге, если Вам интересно: http://splinter.com.au/adding-a-column-to-a-massive-sql-server-table

0
ответ дан Chris 7 November 2019 в 11:05
поделиться

Я использовал бы КУРСОР вместо ОБНОВЛЕНИЯ. Курсор обновит все записи соответствия в пакете, запись записью - это занимает время, но не блокирует таблицу.

, Если Вы хотите избежать, использование блокировок ОЖИДАЕТ.

Также я не уверен, то ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ ограничивают изменения существующие строки. Вероятно, NOT NULL ограничивает использование вместе со случаем причин ПО УМОЛЧАНИЮ, описанным автором.

, Если это изменяется, добавляют его в конце, Таким образом, псевдокод будет похож:

-- without NOT NULL constrain -- we will add it in the end
ALTER TABLE table ADD new_column INT DEFAULT 0

DECLARE fillNullColumn CURSOR LOCAL FAST_FORWARD
    SELECT 
        key
    FROM
        table WITH (NOLOCK)
    WHERE
        new_column IS NULL

OPEN fillNullColumn

DECLARE 
    @key INT

FETCH NEXT FROM fillNullColumn INTO @key

WHILE @@FETCH_STATUS = 0 BEGIN
     UPDATE
         table WITH (ROWLOCK)
     SET
         new_column = 0 -- default value
     WHERE
         key = @key

     WAIT 00:00:05 --wait 5 seconds, keep in mind it causes updating only 12 rows per minute

     FETCH NEXT FROM fillNullColumn INTO @key
END

CLOSE fillNullColumn
DEALLOCATE fillNullColumn

ALTER TABLE table ALTER COLUMN new_column ADD CONSTRAIN xxx

я уверен, что существуют некоторые синтаксические ошибки, но я надеюсь что эта справка для решения проблемы.

Удачи!

-1
ответ дан Grzegorz Gierlik 7 November 2019 в 11:05
поделиться

Сегмент Vertically таблица. Это означает, что у Вас будет две таблицы с тем же первичным ключом, и точно тем же количеством записей... Каждый будет тем, который Вы уже имеете, другой будет иметь просто ключ и новый столбец Non-Null (со значением по умолчанию). Измените всех, Вставляют, Обновление, и удаляют код, таким образом, они сохраняют эти две таблицы в синхронизации... Если Вы хотите Вас, может создать представление, которое "присоединяется" к этим двум таблицам вместе для создания единственной логической комбинации двух, которая появляется как единственная таблица для клиентских операторов Select...

-3
ответ дан Charles Bretana 7 November 2019 в 11:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: