Znalazłem kilka źródeł, które informują, że ALTER TABLE ... DROP COLUMN jest operacją tylko dla metadanych.
Jak to może być? Czy dane podczas DROP COLUMN nie muszą być usuwane z leżących u ich podstaw indeksów nieklastrowych i indeksów klastrowych / sterty?
Ponadto, dlaczego Dokumenty Microsoft sugerują, że jest to w pełni zalogowana operacja?
Zmiany wprowadzone w tabeli są rejestrowane i można je w pełni odzyskać. Zmiany, które wpływają na wszystkie wiersze w dużych tabelach, takie jak upuszczanie kolumny lub, w niektórych wersjach SQL Server, dodawanie kolumny NOT NULL z wartością domyślną, mogą zająć dużo czasu, aby zakończyć i wygenerować wiele rekordów dziennika . Uruchom te instrukcje ALTER TABLE z taką samą ostrożnością jak każda instrukcja INSERT, UPDATE lub DELETE, która wpływa na wiele wierszy.
Drugie pytanie: w jaki sposób silnik śledzi upuszczone kolumny, jeśli dane nie są usuwane z podstawowych stron?
źródło
Odpowiedzi:
Istnieją pewne okoliczności, w których usunięcie kolumny może być operacją tylko dla metadanych. Definicje kolumn dla dowolnej tabeli nie są zawarte na każdej stronie, na której przechowywane są wiersze, definicje kolumn są przechowywane tylko w metadanych bazy danych, w tym sys.sysrowsets, sys.sysrscols itp.
Podczas upuszczania kolumny, do której nie odwołuje się żaden inny obiekt, silnik pamięci po prostu zaznacza definicję kolumny jako już nieobecną, usuwając odpowiednie szczegóły z różnych tabel systemowych. Operacja usunięcia metadanych unieważnia pamięć podręczną procedury, wymagając ponownej kompilacji za każdym razem, gdy zapytanie odwołuje się następnie do tej tabeli. Ponieważ rekompilacja zwraca tylko te kolumny, które obecnie istnieją w tabeli, nigdy nawet nie jest wymagane podanie szczegółów kolumny dla upuszczonej kolumny; silnik pamięci pomija bajty zapisane na każdej stronie dla tej kolumny, tak jakby kolumna już nie istniała.
Gdy wystąpi kolejna operacja DML względem tabeli, strony, których to dotyczy, są ponownie zapisywane bez danych dla upuszczonej kolumny. Jeśli odbudujesz indeks klastrowy lub stertę, wszystkie bajty upuszczonej kolumny nie zostaną oczywiście zapisane z powrotem na stronie na dysku. To skutecznie rozkłada obciążenie związane z upuszczaniem kolumny w czasie, co czyni ją mniej zauważalną.
Istnieją okoliczności, w których nie można upuścić kolumny, na przykład gdy kolumna jest zawarta w indeksie lub gdy ręcznie utworzono obiekt statystyki dla kolumny. Napisałem post na blogu pokazujący błąd, który pojawia się podczas próby zmiany kolumny ręcznie utworzonym obiektem statystycznym. Ta sama semantyka obowiązuje przy upuszczaniu kolumny - jeśli do kolumny odwołuje się jakikolwiek inny obiekt, nie można jej po prostu usunąć. Obiekt odniesienia należy najpierw zmienić, a następnie upuścić kolumnę.
Jest to dość łatwe do pokazania, patrząc na zawartość dziennika transakcji po upuszczeniu kolumny. Poniższy kod tworzy tabelę z pojedynczą kolumną znaków o długości 8 000 znaków. Dodaje wiersz, upuszcza go i wyświetla zawartość dziennika transakcji dotyczącą operacji upuszczania. Rekordy dziennika pokazują modyfikacje różnych tabel systemowych, w których przechowywane są definicje tabel i kolumn. Jeśli dane kolumny faktycznie zostały usunięte ze stron przypisanych do tabeli, zobaczysz rekordy dziennika rejestrujące rzeczywiste dane strony; nie ma takich zapisów.
(Dane wyjściowe są zbyt duże, aby je wyświetlić, a plik dbfiddle.uk nie pozwoli mi uzyskać dostępu do fn_dblog)
Pierwszy zestaw danych wyjściowych pokazuje dziennik jako wynik instrukcji DDL upuszczającej kolumnę. Drugi zestaw danych wyjściowych pokazuje dziennik po uruchomieniu instrukcji DML, w której aktualizujemy
rid
kolumnę. W drugim zestawie wyników widzimy rekordy dziennika wskazujące usunięcie z dbo.DropColumnTest, a następnie wstawienie do dbo.DropColumnTest. Długość każdego dziennika wynosi 8116, co oznacza, że rzeczywista strona została zaktualizowana.Jak widać z danych wyjściowych
fn_dblog
polecenia w powyższym teście, cała operacja jest w pełni rejestrowana. Dotyczy to zarówno prostego odzyskiwania, jak i pełnego odzyskiwania. Terminologia „w pełni zalogowana” może być źle interpretowana, ponieważ modyfikacja danych nie jest rejestrowana. Tak się nie dzieje - modyfikacja jest rejestrowana i można ją w pełni wycofać. Dziennik po prostu rejestruje tylko te strony, które zostały dotknięte, a ponieważ żadna ze stron danych tabeli nie została zarejestrowana przez operację DDL, zarówno, jakDROP COLUMN
i wszelkie wycofywanie, które może nastąpić, nastąpi niezwykle szybko, niezależnie od wielkości tabeli.W przypadku nauki poniższy kod zrzuci strony danych dla tabeli zawartej w powyższym kodzie, używając
DBCC PAGE
stylu „3”. Styl „3” oznacza, że chcemy nagłówka strony oraz szczegółowej interpretacji dla poszczególnych wierszy . Kod używa kursora, aby wyświetlić szczegóły każdej strony w tabeli, więc możesz chcieć się upewnić, że nie uruchomisz tego na dużym stole.Patrząc na wynik pierwszej strony z mojej wersji demonstracyjnej (po upuszczeniu kolumny, ale przed aktualizacją kolumny), widzę to:
Dla zwięzłości usunąłem większość surowego zrzutu strony z danych wyjściowych pokazanych powyżej. Na końcu danych wyjściowych zobaczysz to dla
rid
kolumny:Ostatni wiersz powyżej
rid = 1
zwraca nazwę kolumny i bieżącą wartość przechowywaną w kolumnie na stronie.Następnie zobaczysz to:
Wynik pokazuje, że Slot 0 zawiera usuniętą kolumnę na podstawie
DELETED
tekstu, w którym normalnie byłaby nazwa kolumny. Wartość kolumny jest zwracana,NULL
ponieważ kolumna została usunięta. Jednak, jak widać w surowych danych, wartość 8 000 znakówREPLICATE('Z', 8000)
dla tej kolumny nadal istnieje na stronie. To jest przykład tej części wyniku DBCC PAGE:źródło