Я нашел несколько источников, которые утверждают, что ALTER TABLE ... DROP COLUMN - это операция только с метаданными.
Как это может быть? Не нужно ли удалять данные во время DROP COLUMN из базовых некластеризованных индексов и кластеризованного индекса / кучи?
Кроме того, почему Microsoft Docs подразумевает, что это полностью зарегистрированная операция?
Изменения, внесенные в таблицу, регистрируются и полностью восстанавливаются. Изменения, затрагивающие все строки в больших таблицах, такие как удаление столбца или добавление столбца NOT NULL со значением по умолчанию в некоторых выпусках SQL Server, могут занять много времени и создать много записей журнала . Запустите эти операторы ALTER TABLE с той же тщательностью, что и любой оператор INSERT, UPDATE или DELETE, который влияет на множество строк.
В качестве дополнительного вопроса: как движок отслеживает пропущенные столбцы, если данные не удаляются с нижележащих страниц?
источник
Ответы:
Существуют определенные обстоятельства, при которых удаление столбца может быть операцией только с метаданными. Определения столбцов для любой данной таблицы не включены в каждую страницу, где хранятся строки, определения столбцов хранятся только в метаданных базы данных, включая sys.sysrowsets, sys.sysrscols и т. Д.
При удалении столбца, на который не ссылается какой-либо другой объект, механизм хранения просто помечает определение столбца как более не присутствующее, удаляя соответствующие данные из различных системных таблиц. Действие удаления метаданных делает недействительным кеш процедуры, что требует повторной компиляции всякий раз, когда запрос впоследствии ссылается на эту таблицу. Поскольку перекомпиляция возвращает только те столбцы, которые в настоящий момент существуют в таблице, сведения о столбцах для удаленного столбца даже не запрашиваются; механизм хранения пропускает байты, хранящиеся на каждой странице для этого столбца, как будто столбец больше не существует.
Когда с таблицей происходит последующая операция DML, затронутые страницы перезаписываются без данных для отброшенного столбца. Если вы перестраиваете кластерный индекс или кучу, все байты для отброшенного столбца, естественно, не записываются обратно на страницу на диске. Это эффективно распределяет нагрузку от падения колонны с течением времени, делая ее менее заметной.
Существуют обстоятельства, когда вы не можете удалить столбец, например, когда столбец включен в индекс или когда вы вручную создали объект статистики для столбца. Я написал сообщение в блоге, в котором показана ошибка, возникающая при попытке изменить столбец с помощью созданного вручную объекта статистики. Та же семантика применяется при удалении столбца - если на столбец ссылается какой-либо другой объект, его нельзя просто удалить. Ссылочный объект должен быть сначала изменен, затем столбец может быть удален.
Это довольно легко показать, посмотрев содержимое журнала транзакций после удаления столбца. Приведенный ниже код создает таблицу с одним столбцом длиной 8 000 символов. Он добавляет строку, затем удаляет ее и отображает содержимое журнала транзакций, применимого к операции удаления. Записи журнала показывают модификации различных системных таблиц, в которых хранятся определения таблиц и столбцов. Если данные столбца фактически удаляются со страниц, выделенных для таблицы, вы увидите записи журнала, в которых записаны фактические данные страницы; таких записей нет
(Вывод слишком велик, чтобы показать здесь, и dbfiddle.uk не позволит мне получить доступ к fn_dblog)
Первый набор выходных данных показывает журнал как результат того, что оператор DDL отбрасывает столбец. Второй набор выходных данных показывает журнал после выполнения инструкции DML, где мы обновляем
rid
столбец. Во втором наборе результатов мы видим записи в журнале, указывающие на удаление для dbo.DropColumnTest, за которым следует вставка в dbo.DropColumnTest. Длина каждой записи журнала - 8116, что указывает на то, что фактическая страница была обновлена.Как вы можете видеть на выходе
fn_dblog
команды в вышеупомянутом тесте, вся операция будет полностью вошла. Это касается простого восстановления, а также полного восстановления. Терминология «полностью зарегистрировано» может быть неверно истолкована, поскольку изменение данных не зарегистрировано. Это не то , что происходит - изменение в журнале, и может быть полностью откат. В журнале просто записываются только те страницы, к которым было выполнено прикосновение, и поскольку ни одна из страниц данных таблицы не была записана с помощью операции DDL, тоDROP COLUMN
и откат, и любой возможный откат могут произойти очень быстро, независимо от размера таблицы.Для науки , следующий код выведет страницы данных для таблицы, включенной в код выше, используя
DBCC PAGE
стиль «3». Стиль «3» указывает на то, что нам нужен заголовок страницы плюс подробная интерпретация для каждой строки . Код использует курсор для отображения деталей для каждой страницы в таблице, поэтому вы можете убедиться, что вы не запускаете это на большой таблице.Глядя на вывод для первой страницы из моей демонстрации (после удаления столбца, но до обновления столбца), я вижу это:
Для краткости я удалил большую часть дампа необработанных страниц из вывода, показанного выше. В конце вывода вы увидите это для
rid
столбца:Последняя строка выше,
rid = 1
возвращает имя столбца и текущее значение, сохраненное в столбце на странице.Далее вы увидите это:
Выходные данные показывают, что слот 0 содержит удаленный столбец, благодаря
DELETED
тексту, где обычно находится имя столбца. Значение столбца возвращается, такNULL
как столбец был удален. Однако, как вы можете видеть из необработанных данныхREPLICATE('Z', 8000)
, для этой колонки все еще существует значение длиной 8000 символов . Это пример той части вывода DBCC PAGE:источник