Добавить новый столбец в таблицу большой базы данных

Мне нужно добавить новый столбец в таблицу в моей базе данных. В таблице содержится около 140 миллионов строк, и я не уверен, как действовать без блокировки базы данных.

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

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

Я бы очень оценил некоторые прямые ответы на этот вопрос. Это выполнимо или нет?

Ответы

Ответ 1

Да, это действительно выполнимо.

Добавление столбца, где NULL является приемлемым и не имеет значения по умолчанию, не требует долговременной блокировки для добавления данных в таблицу.

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

Как это работает вообще:

+---------------------+------------------------+-----------------------+
| Column is Nullable? | Default Value Supplied | Result                |
+---------------------+------------------------+-----------------------+
| Yes                 | No                     | Quick Add (caveat)    |
| Yes                 | Yes                    | Long running lock     |
| No                  | No                     | Error                 |
| No                  | Yes                    | Long running lock     |
+---------------------+------------------------+-----------------------+

Предостережение:

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

Изменить → @MartinSmith указал, что растровое изображение NULL будет расширяться только при изменении строки, большое спасибо. Однако, как он также указывает, если размер строки расширяется за пределы байта 8060 байтов в SQL Server 2012, тогда может потребоваться длительная блокировка. Большое спасибо * 2.

Вторая оговорка:

Проверьте его.

Третий и последний оговорки:

Нет, проверьте его.

Ответ 2

Мой пример: как добавить новый столбец в таблицу десятками миллионов строк и заполнить его по умолчанию без длительной блокировки

USE [MyDB]
GO

ALTER TABLE [dbo].[Customer] ADD [CustomerTypeId] TINYINT NULL
GO
ALTER TABLE [dbo].[Customer] ADD CONSTRAINT [DF_Customer_CustomerTypeId] DEFAULT 1 FOR [CustomerTypeId]
GO
DECLARE @batchSize bigint = 5000
    ,@rowcount int
    ,@MaxID int;

SET @rowcount = 1
SET @MaxID = 0

WHILE @rowcount > 0
BEGIN
    ;WITH upd as (
        SELECT TOP (@batchSize)
            [ID]
            ,[CustomerTypeId]
        FROM [dbo].[Customer] (NOLOCK)
        WHERE [CustomerTypeId] IS NULL
            AND [ID] > @MaxID
        ORDER BY [ID])

    UPDATE upd
          SET [CustomerTypeId] = 1
              ,@MaxID = CASE WHEN [ID] > @MaxID THEN [ID] ELSE @MaxID END

    SET @rowcount = @@ROWCOUNT
    WAITFOR DELAY '00:00:01'
END;

ALTER TABLE [dbo].[Customer]  ALTER COLUMN [CustomerTypeId] TINYINT NOT NULL;
GO

ALTER TABLE [dbo].[Customer] ADD [CustomerTypeId] TINYINT NULL изменяет только метаданные (замки Sch-M) и время блокировки не зависит от количества строк в таблице

После этого я заполняю новый столбец по умолчанию небольшими порциями (5000 строк). Я жду одну секунду после каждого цикла, чтобы не блокировать таблицу слишком агрессивно. У меня есть идентификатор столбца int в качестве основного кластерного ключа

Наконец, когда заполняется весь новый столбец, я меняю его на NOT NULL

Ответ 3

Никто не может сказать, сколько времени будет стоить операция, так как это зависит от многих факторов.

Вы не должны беспокоиться о самих операциях, потому что SQL Server делает все правильно:

Механизм Database Engine использует блокировку модификации схемы (Sch-M) во время (DDL), например, добавление столбец или отбрасывание таблицы. В течение времени, которое он проводит, Sch-M блокировка предотвращает параллельный доступ к таблице. Это означает, что Sch-M блокировка блокирует все внешние операции до тех пор, пока блокировка не будет отпущена.

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

ИЗМЕНИТЬ:

Здесь вы можете найти дополнительную информацию о своем вопросе. Как правило, Matt Whitfield является правильным и

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

и когда

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

Ответ 4

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