Я столкнулся с этой проблемой и в своей работе. И мое решение соответствует пункту 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.
Вот то, что я попробовал бы:
использование ПРОСТОЙ модели восстановления не прекращает регистрироваться, но это значительно уменьшает свое влияние. Это вызвано тем, что сервер отбрасывает информацию о восстановлении после каждой фиксации.
Вы могли:
преимущество этого подхода состоит в том, что Ваши читатели будут в состоянии получить доступ к таблице во время долгого процесса и что можно выполнить любой вид изменения схемы в фоновом режиме.
Я думаю, что это зависит от разновидности SQL, которую Вы используете, но что, если Вы взяли опцию 2, но в самом конце, изменяют таблицу таблицы к не пустой со значением по умолчанию?
это было бы быстро, так как это видит, что все значения не являются пустыми?
Если Вы хотите столбец в той же таблице, необходимо будет просто сделать это. Теперь, опция 3 является потенциально лучшей для этого, потому что у Вас может все еще быть база данных, "живая", в то время как эта операция продолжается. При использовании опции 1 таблица заблокирована, в то время как операция происходит, и затем Вы действительно застреваете.
, Если Вы действительно не заботитесь, находится ли столбец в таблице, то я предполагаю, сегментированный подход является следующим лучше всего. Хотя, я действительно стараюсь избегать этого (до такой степени, что я не делаю этого), потому что тогда как Charles Bretana говорит, необходимо будет удостовериться и найти все места, которые обновляют/вставляют ту таблицу и изменяют тех. Тьфу!
Я имел подобную проблему и пошел для Вашей опции № 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
Я использовал бы КУРСОР вместо ОБНОВЛЕНИЯ. Курсор обновит все записи соответствия в пакете, запись записью - это занимает время, но не блокирует таблицу.
, Если Вы хотите избежать, использование блокировок ОЖИДАЕТ.
Также я не уверен, то ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ ограничивают изменения существующие строки. Вероятно, 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
я уверен, что существуют некоторые синтаксические ошибки, но я надеюсь что эта справка для решения проблемы.
Удачи!
Сегмент Vertically таблица. Это означает, что у Вас будет две таблицы с тем же первичным ключом, и точно тем же количеством записей... Каждый будет тем, который Вы уже имеете, другой будет иметь просто ключ и новый столбец Non-Null (со значением по умолчанию). Измените всех, Вставляют, Обновление, и удаляют код, таким образом, они сохраняют эти две таблицы в синхронизации... Если Вы хотите Вас, может создать представление, которое "присоединяется" к этим двум таблицам вместе для создания единственной логической комбинации двух, которая появляется как единственная таблица для клиентских операторов Select...