Как добавить столбец в таблицу больших sql-серверов

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

Синтаксически это не проблема, и если в таблице не было так много строк и не было в производстве, это было бы легко.

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

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

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

Ответ 1

ALTER TABLE table1 ADD
  newcolumn int NULL
GO

не стоит так долго... Что займет много времени, так это вставить столбцы в середине других столбцов... b/c, тогда движок должен создать новую таблицу и скопировать данные в новую таблицу.

Ответ 2

Единственное реальное решение для непрерывного времени бесперебойной работы - это резервирование.

Я признаю, что @Nestor отвечает, что добавление нового столбца не должно занять много времени в SQL Server, но, тем не менее, оно все равно может быть отключением, которое неприемлемо для производственной системы. Альтернативой является изменение в параллельной системе, а затем, как только операция будет завершена, замените новое для старого.

Например, если вам нужно добавить столбец, вы можете создать копию таблицы, затем добавить столбец в эту копию, а затем использовать sp_rename(), чтобы переместить старый стол в сторону и новую таблицу на место.

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

Для некоторых видов сложных обновлений вы можете полностью дублировать базу данных на отдельном сервере. Как только это будет готово, просто замените записи DNS для двух серверов и voilà!

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

Ответ 3

"Добавьте столбец, а затем выполните относительно небольшие пакеты UPDATE, чтобы заполнить столбец значением по умолчанию. Это должно предотвратить любые заметные замедления"

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

Вы можете переименовать текущую таблицу с X на Y. Вы можете сделать это с помощью этой команды: sp_RENAME '[OldTableName]', '[NewTableName]'.

Создайте новую таблицу как X с новым столбцом, установленным в NOT NULL, а затем вставьте пакет из Y в X и включите значение по умолчанию либо в свою вставку для нового столбца, либо поместите значение по умолчанию в новый столбец при воссоздании таблица X.

Я сделал этот тип изменений на таблице с сотнями миллионов строк. Это продолжалось более часа, но это не привело к взрыву нашего журнала. Когда я попытался просто изменить столбец на NOT NULL со всеми данными в таблице, потребовалось более 20 часов, прежде чем я убил процесс.

Тестировали ли вы просто добавление столбца, заполняющего его данными, и установку столбца NOT NULL?

Поэтому, в конце концов, я не думаю, что там волшебная пуля.

Ответ 4

Я не хотел, чтобы столбец разрешал null, что означало бы, что мне нужно иметь значение по умолчанию.

Добавление столбца NOT NULL с DEFAULT Ограничением в таблицу любого количества строк (даже миллиарды) стало намного проще, начиная с SQL Server 2012 (но только для Enterprise Edition), поскольку они позволяли ему быть Операция в режиме онлайн (в большинстве случаев), где для существующих строк значение будет считываться из метаданных и фактически не сохраняется в строке до тех пор, пока строка не будет обновлена, или кластеризованный индекс не будет восстановлен. Вместо парафраза, вот соответствующий раздел со страницы MSDN для ALTER TABLE:

Добавление NOT NULL столбцов в качестве онлайн-операции

Начиная с SQL Server 2012 Enterprise Edition добавление столбца NOT NULL со значением по умолчанию - это онлайн-операция, когда значением по умолчанию является константа времени выполнения. Это означает, что операция выполняется почти мгновенно, независимо от количества строк в таблице. Это связано с тем, что существующие строки в таблице не обновляются во время операции; вместо этого значение по умолчанию сохраняется только в метаданных таблицы, и значение просматривается по мере необходимости в запросах, которые обращаются к этим строкам. Такое поведение происходит автоматически; дополнительный синтаксис не требуется для реализации онлайн-операции за синтаксисом ADD COLUMN. Константа времени выполнения - это выражение, которое производит одно и то же значение во время выполнения для каждой строки таблицы независимо от ее детерминизма. Например, константное выражение "Мои временные данные" или системная функция GETUTCDATETIME() являются константами времени выполнения. Напротив, функции NEWID() или NEWSEQUENTIALID() не являются константами времени выполнения, поскольку для каждой строки таблицы создается уникальное значение. Добавление столбца NOT NULL со значением по умолчанию, который не является константой времени выполнения, всегда выполняется в автономном режиме, а эксклюзивная (SCH-M) блокировка выполняется на время операции.

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

Колонки типа varchar (max), nvarchar (max), varbinary (max), xml, text, ntext, image, hierarchyid, геометрия, география или CLR UDTS не могут быть добавлены в онлайн-операции. Столбец нельзя добавить в сеть, если это приводит к тому, что максимально возможный размер строки превышает предел в 8,060 байт. В этом случае столбец добавляется как автономная операция.

Ответ 5

выберите в новую таблицу и переименуйте. Пример. Добавление столбца я в таблицу A:

select *, 1 as i
into A_tmp
from A_tbl

//Add any indexes here

exec sp_rename 'A_tbl', 'A_old'
exec sp_rename 'A_tmp', 'A_tbl'

Быть быстрым и не трогать журнал транзакций, например, вставлять его партиями. (Я просто сделал это сегодня с 70-миллионной таблицей строк в < 2 мин).

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

Ответ 6

Другой метод заключается в том, чтобы добавить столбец в новую связанную таблицу (предположим, что отношение "один к одному" вы можете обеспечить, предоставив FK уникальный индекс). Затем вы можете заполнить это партиями, а затем вы можете добавить соединение в эту таблицу, где бы вы ни хотели, чтобы данные отображались. Примечание. Я бы рассматривал это только для столбца, который я бы не хотел использовать в каждом запросе в исходной таблице, или если ширина записи моей исходной таблицы становилась слишком большой или добавлялась несколько столбцов.