Database
 sql >> Baza danych >  >> RDS >> Database

Minimalizowanie wpływu poszerzenia kolumny TOŻSAMOŚĆ – część 2

[ Część 1 | Część 2 | Część 3 | Część 4 ]

W pierwszej części tej serii pokazałem, co dzieje się z fizyczną stroną po zmianie kolumny IDENTITY z int na bigint. Aby wszystko było proste, stworzyłem bardzo prostą stertę bez indeksów i ograniczeń. Niestety, większość z nas nie ma takiego luksusu – ważny stół, który musi się zmienić, ale nie można go po prostu odtworzyć od zera, prawdopodobnie ma wiele atrybutów stojących bezpośrednio na naszej drodze. W tym poście chciałem pokazać te bardziej popularne, nawet bez wchodzenia w egzotyczne rzeczy, takie jak OLTP w pamięci i Columnstore.

Klucz główny

Mam nadzieję, że wszystkie twoje tabele mają klucz podstawowy; jeśli jednak w grę wchodzi kolumna IDENTITY, nie będzie łatwo zmienić bazowy typ danych. Weź te proste przykłady, zarówno klastrowe, jak i nieklastrowe klucze podstawowe:

UTWÓRZ TABELĘ dbo.Test1(ID INT IDENTITY(1,1), OGRANICZENIE PK_1 KLUCZ PODSTAWOWY NIESKLASTRAROWANY (ID)); CREATE TABLE dbo.Test2( ID INT IDENTITY (1,1), CONSTRAINT PK_2 PRIMARY KEY CLASTERED (ID));

Jeśli spróbuję zmienić kolumnę:

ALTER TABLE dbo.Test1 ALTER COLUMN ID BIGINT; GOALTER TABLE dbo.Test2 ALTER COLUMN ID BIGINT;

Otrzymuję parę komunikatów o błędach dla każdej ALTER (pokazuje tylko pierwszą parę):

Msg 5074, Poziom 16, Stan 1
Obiekt 'PK_1' jest zależny od kolumny 'ID'.
Msg 4922, Poziom 16, Stan 9
ALTER TABLE ALTER COLUMN ID nie powiodło się, ponieważ jeden lub więcej obiektów ma dostęp do tej kolumny.

Podsumowanie:będziemy musieli usunąć klucz podstawowy , niezależnie od tego, czy jest zgrupowany.

Indeksy

Najpierw weźmy kilka tabel jak powyżej, używając unikalnego indeksu zamiast klucza podstawowego:

CREATE TABLE dbo.Test3(ID INT IDENTITY(1,1), INDEX IX_3 UNIQUE NIEKLASTERY (ID)); CREATE TABLE dbo.Test4( ID INT IDENTITY(1,1), INDEX IX_4 UNIQUE CLUSTERED (ID) );

Uruchomienie podobnych poleceń ALTER powyżej prowadzi do tych samych komunikatów o błędach. Pozostaje to prawdą, nawet jeśli wyłączę indeksy:

ZMIEŃ INDEKS IX_3 NA dbo.Test3 WYŁĄCZ; INDEKS GOALTER IX_4 NA dbo.Test4 WYŁĄCZ;

Podobne wyniki dla różnych innych typów kombinacji indeksów, takich jak dołączona kolumna lub filtr:

CREATE TABLE dbo.Test5(ID INT IDENTITY(1,1), x CHAR(1));CREATE INDEX IX_5 ON dbo.Test5(x) INCLUDE(ID); CREATE TABLE dbo.Test6( ID INT IDENTITY(1,1), x CHAR(1));CREATE INDEX IX_6 ON dbo.Test6(x) WHERE ID> 0;

Podsumowanie:będziemy musieli usunąć i ponownie utworzyć wszystkie indeksy , klastrowane lub nie, które odwołują się do kolumny IDENTITY — w kluczu lub w INCLUDE. Jeśli kolumna IDENTITY jest częścią indeksu klastrowego, oznacza to wszystkie indeksy , ponieważ wszystkie z definicji odwołują się do klucza klastrowania. A samo ich wyłączenie nie wystarczy.

Kolumny obliczane

Chociaż powinno to być stosunkowo rzadkie, widziałem kolumny obliczone na podstawie kolumny IDENTITY. Na przykład:

CREATE TABLE dbo.Test7(ID INT IDENTITY(1,1), NextID AS (ID+1));

Tym razem, gdy próbujemy zmienić, otrzymujemy tę samą parę błędów, ale z nieco innym tekstem:

Msg 5074, Poziom 16, Stan 1
Kolumna „NextID” jest zależna od kolumny „ID”.
Msg 4922, Level 16, State 9
ALTER TABLE ALTER COLUMN ID nie powiodło się, ponieważ jeden lub więcej obiektów ma dostęp do tej kolumny.

Dzieje się tak nawet wtedy, gdy zmienimy definicję kolumny wyliczanej w celu dopasowania do docelowego typu danych:

CREATE TABLE dbo.Test8(ID INT IDENTITY(1,1), NextID AS (CONVERT(BIGINT, ID) + 1));

Podsumowanie:będziemy musieli zmienić definicje kolumn obliczanych lub całkowicie je usunąć.

Wyświetlenia zindeksowane

Zindeksowane widoki pokazują również ich sprawiedliwy udział w użyciu. Skonstruujmy widok indeksowany, który nawet nie odwołuje się do kolumny IDENTITY (zwróć uwagę, że nie ma innych indeksów ani ograniczeń w tabeli bazowej):

CREATE TABLE dbo.Test9(ID INT IDENTITY(1,1), x CHAR(1));GO CREATE VIEW dbo.vTest9AWITH SCHEMABINDINGAS SELECT x, c =COUNT_BIG(*) FROM dbo.Test9 GROUP BY x;GO UTWÓRZ UNIKATOWY SKLASTROWANY INDEKS IX_9A NA dbo.vTest9A(x);

Jeszcze raz spróbujemy ALTER i tym razem to się uda . Przyznam się, że byłem tym zaskoczony, ponieważ funkcja SCHEMABINDING ma zapobiegać wszelkim zmianom w tabeli bazowej, ale w tym przypadku dotyczy tylko kolumn, do których wyraźnie odwołuje się widok. Jeśli stworzymy nieco inny widok:

UTWÓRZ WIDOK dbo.vTest9B Z POWIĄZANIAMI SCHEMATÓW JAKO SELECT ID, c =COUNT_BIG(*) Z dbo.Test9 GRUPUJ WEDŁUG ID; 

Teraz nie powiedzie się z powodu zależności kolumn:

Msg 5074, poziom 16, stan 1
Obiekt „vTest9B” jest zależny od kolumny „ID”.
Wiadomość 4922, poziom 16, stan 9
ALTER TABLE ALTER COLUMN ID nie powiodło się, ponieważ jeden lub więcej obiektów ma dostęp do tej kolumny.

Podsumowanie:będziemy musieli usunąć wszystkie indeksy we wszystkich widokach, które wyraźnie odwołują się do kolumny IDENTITY , a także wszystkie indeksy w dowolnym widoku, który odwołuje się do kolumny IDENTITY w swoim indeksie klastrowym.

Przychodzące klucze obce

Prawdopodobnie najbardziej problematycznym aspektem kluczy podstawowych TOŻSAMOŚCI jest to, że ze względu na samą naturę surogatów chodzi o to, aby często używać tego klucza zastępczego w wielu powiązanych tabelach. Nie mam zamiaru opowiadać się za unikaniem uczciwości referencyjnej, ale w tym przypadku może to również trochę stanąć na naszej drodze. Wiemy z góry, że nie możemy zmienić kolumny, która jest częścią klucza podstawowego lub ograniczenia przez unikalność, a aby kolejna tabela wskazywała tutaj z ograniczeniem klucza obcego, musi istnieć jedna z tych dwóch rzeczy. Załóżmy więc, że mamy następujące dwie tabele:

CREATE TABLE dbo.TestParent(ID INT IDENTITY(1,1), CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED(ID));GO CREATE TABLE dbo.TestChild( ParentID INT NOT NULL, OGRANICZENIE FK_Parent FOREIGN KEY (ParentID) REFERENCES dbo. TestParent(ID));

Zanim będziemy mogli nawet rozważyć zmianę typu danych kolumny, musimy usunąć ograniczenie:

ZMIEŃ TABELĘ dbo.TestParent OGRANICZENIE UPUSZCZANIA PK_Parent;

I oczywiście nie możemy, bez usunięcia ograniczenia klucza obcego, ponieważ powoduje to wyświetlenie następującego komunikatu o błędzie:

Komunikat 3725, poziom 16, stan 0
Do ograniczenia „PK_Parent” odwołuje się tabela „TestChild”, ograniczenie klucza obcego „FK_Parent”.
Komunikat 3727, poziom 16, stan 0
Może nie upuść ograniczenia. Zobacz poprzednie błędy.

Ten błąd pozostaje, nawet jeśli najpierw wyłączymy ograniczenie klucza obcego:

ALTER TABELA dbo.TestChild NOCHECK CONSTRAINT FK_Parent;

Oprócz tego należy pamiętać, że do zmiany typu danych będą potrzebne również kolumny z odwołaniami. Co więcej, te kolumny prawdopodobnie uczestniczą w niektórych z powyższych elementów, które mogą podobnie zapobiegać zmianom w tabelach podrzędnych. Aby wszystko było w pełni zgodne i zsynchronizowane, musimy:

  • upuść odpowiednie ograniczenia i indeksy w tabeli nadrzędnej
  • upuść odpowiednie ograniczenia klucza obcego w tabelach podrzędnych
  • upuść wszystkie indeksy w tabelach podrzędnych, które odwołują się do kolumny FK (i zajmują się wszelkimi odpowiednimi kolumnami obliczeniowymi / widokami indeksowanymi)
  • zmień typ danych w tabelach nadrzędnych i wszystkich tabelach podrzędnych
  • odtwórz wszystko

Podsumowanie:będziemy musieli usunąć przychodzące klucze obce i potencjalnie będzie to miało cały szereg efektów kaskadowych. Samo wyłączenie kluczy obcych nie wystarczy i i tak nie byłoby trwałym rozwiązaniem, ponieważ typ danych będzie musiał się w końcu zmienić również w tabelach podrzędnych.

Wniosek

Wiem, że wygląda na to, że idziemy powoli, i przyznaję, że w tym poście wydaje mi się, że oddalam się od rozwiązania, a nie w jego kierunku. Dojdę do tego, jest tylko dużo informacji do zaprezentowania na początku, w tym rzeczy, które utrudniają tego typu zmianę. Pobrane z powyższych podsumowań, musimy:

  • upuść i ponownie utwórz odpowiednie indeksy w głównej tabeli
  • zmień lub usuń kolumny obliczone, które obejmują kolumnę IDENTITY
  • upuść indeksy w zindeksowanych widokach, które odwołują się do kolumny IDENTITY
  • radzić sobie z przychodzącymi kluczami obcymi, które wskazują na kolumnę IDENTITY

Niestety wiele z tych rzeczy to paragraf 22. Nie możesz zmienić kolumny, ponieważ indeks na niej opiera się, i nie możesz zmienić indeksu, dopóki kolumna się nie zmieni. Czy nie byłoby wspaniale, gdyby ALTER INDEX obsługiwał REBUILD WITH (ONLINE = ON, CHANGE_COLUMN (COLUMN = ID, NEW_TYPE = BIGINT)) ? Oraz CASCADE_CHANGE_TO_REFERENCING_KEYS,COLUMNS,INDEXES,VIEWS,ETC ? Cóż, nie (sprawdziłem). Dlatego musimy znaleźć sposoby na ułatwienie tych rzeczy. Czekajcie na część 3.

[ Część 1 | Część 2 | Część 3 | Część 4 ]


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zaktualizowane opcje warstwy bazy danych Azure SQL

  2. Przywracanie przykładowej bazy danych DW AdventureWorksDW2019

  3. Używanie OAuth do uwierzytelniania połączenia ODBC z Salesforce.com

  4. Czy Twoja baza danych jest zabezpieczona? Pomyśl jeszcze raz

  5. Model danych dla aplikacji do rezerwacji wizyt lekarskich