sql >> Databasteknik >  >> RDS >> Sqlserver

Begränsa datatyperna på ett mycket stort bord

Först och främst, tack för att du gör detta. Det är en så självklar vinst som många inte skulle se mycket värde i, men det kommer att vara väl värt det :). Gör världen lite sundare.

Angående IsActive vara en boolean. Min gissning är att du funderar på att göra det till en BIT fält. Det kan vara vägen att gå, men ibland är det bättre att gå med TINYINT eftersom det finns möjlighet att utöka betydelsen till mer än 2 tillstånd. I så fall blir det verkligen mer av StatusID . Vanligtvis handlar det om något som förenklat börjar som aktivt / Inaktiv , men senare kanske Raderad och/eller andra. Ur ett storleksperspektiv, TINYINT är alltid 1 byte. Å andra sidan, BIT är 1 byte för upp till 8 BIT fält . Det betyder en BIT fältet är 1 byte, 2 BIT fält är också en byte, och så vidare upp till 8 BIT fält som lagras i en enda byte. Så det finns ingen platsbesparing genom att välja BIT över TINYINT när tabellen bara har 1 BIT fält. Bara något att tänka på.

Att göra ett ALTER TABLE är lite mycket för ett stort bord, som du såg. Ett alternativ, även om det inte är bra, är att lägga till en NOT NULL field--Number_1new --med en DEFAULT värde (detta kommer att vara omedelbart på grund av standardinställningen, åtminstone från och med SQL 2012) som ingen av dem naturligt skulle ha (t.ex. 255), och sedan långsamt migrera värdena, i en loop, som i:

UPDATE TOP (5000) tab
SET tab.Number_1new = tab.Number_1
FROM [table] tab
WHERE tab.Number_1new = 255;

Och när det är gjort gör du:

sp_rename 'table.Number_1', 'Number_1old', 'COLUMN';
sp_rename 'table.Number_1new', 'Number_1', 'COLUMN';

Naturligtvis, bäst att slå in det i en TRANSAKTION, och det insvept i ett TRY/CATCH. När den relaterade koden har uppdaterats och allt har testats och data ser bra ut kan du släppa Number_1old kolumn.

Det bästa sättet jag har hittat är dock att skapa en ny tabell, långsamt överföra data och sedan byta tabeller och kod samtidigt. Jag beskrev stegen i en artikel om SQL Server Central:Restructure 100 Million Row (eller mer) Tabeller på sekunder. SRSLY! (gratis registrering krävs). Om det skulle uppstå problem med att komma till den artikeln, här är de grundläggande stegen:

  1. Skapa en ny tabell med den idealiska strukturen--[tabellNy]. Om du använder Enterprise Edition, överväg att aktivera antingen ROW- eller PAGE-komprimering eftersom de ibland kan hjälpa. Men snälla gör lite forskning först eftersom det finns vissa situationer när de har en negativ effekt. Det finns dokumentation om MSDN som hjälper dig att ta reda på det samt några verktyg för att uppskatta potentiell besparing. Men även om du aktiverar komprimering, skulle jag inte se den åtgärden som en ersättning för projektet du gör här.
  2. Lägg till en utlösare AFTER UPDATE, DELETE på [tabell] för att hålla ändringar synkroniserade (men du behöver inte oroa dig för nya rader)
  3. Skapa ett SQL Agent Job som flyttar över saknade rader i batcher. Gör detta i en loop som gör en INSERT INTO [tableNew] (Columns) SELECT TOP (n) Columns FROM [table] WHERE ?? ORDER BY ??
  4. Klausulerna WHERE och ORDER BY beror på situationen. De bör vara inriktade på att utnyttja det klustrade indexet på bästa sätt. Om det klustrade indexet för den nya tabellen är strukturellt detsamma som den gamla/nuvarande tabellen, kan du i början av varje slinga hämta MAX([id]) från [tableNew] och använda den för att få WHERE table.[id] > @MaxIdInTableNew ORDER BY table.[id] .
  5. Skapa den nya tabellen, trigga på den aktuella tabellen och SQL Agent Job en vecka eller så innan du behöver göra hela cut-over. Den tidsramen kan ändras beroende på din situation, men se bara till att ge dig själv gott om tid. Det är mycket bättre för jobbet att slutföra migreringen av rader och bara ha några få som droppar in åt gången i stället för att vara 100 000 blyg för hela uppsättningen när releasen ska börja.
  6. Om planen är att migrera de andra relaterade tabellerna (PK-referenserna för de två FK som du vill omvandla till INT s), gör sedan dessa fält här INT nu och lägg bara inte till FK förrän de andra tabellerna har migrerats över till att ha INT-fält som sina PK:er. Du vill inte behöva bygga om den här tabellen igen bara för att göra den ändringen för FK-fälten.
  7. Under cut-over (i en TRY/CATCH, naturligtvis):
    1. BÖRJA TRAN
    2. gör en sista radräkning på båda tabellerna för att se till att allt flyttas över (du kanske vill kontrollera raderna innan releasen för att se till att utlösaren gjorde uppdateringarna och raderna som förväntat)
    3. byt namn på den aktuella tabellen till "gammal"
    4. byt namn på den "nya" tabellen för att inte ha den "nya"
    5. släpp SQL Agent-jobbet (eller åtminstone inaktivera det)
    6. byt namn på och beroende objekt såsom begränsningar, etc.
    7. ÅTGÄRDER


  1. Infoga flera rader UTAN att upprepa INSERT INTO ... delen av påståendet?

  2. Hur påverkar NULL-värden prestanda i en databassökning?

  3. TransactionScope och metodanrop som använder samma anslutning

  4. mysql:Hur man INNER JOIN ett bord men begränsar gå med till 1 resultat med den högsta rösten eller antalet?