sql >> Database >  >> RDS >> Sqlserver

De gegevenstypen op een zeer grote tabel beperken

Allereerst bedankt dat je dit doet. Het is zo'n voor de hand liggende overwinning dat velen er niet veel waarde in zouden zien, maar het zal het zeker waard zijn :). De wereld een beetje gezonder maken.

Over IsActive een boolean zijn. Ik vermoed dat je overweegt er een BIT van te maken veld. Dat is misschien de juiste weg, maar soms is het beter om TINYINT te gebruiken omdat er de mogelijkheid is om de betekenis uit te breiden naar meer dan 2 staten. In dat geval wordt het echt meer een StatusID . Meestal is het een geval van iets dat simplistisch begint als Actief / Inactief , maar later misschien Verwijderd en/of anderen. Vanuit het perspectief van de maatvoering, TINYINT is altijd 1 byte. Aan de andere kant, BIT is 1 byte voor maximaal 8 BIT velden . Betekenis, één BIT veld is 1 byte, 2 BIT velden is ook één byte, enzovoort tot 8 BIT velden worden opgeslagen in een enkele byte. Er is dus geen ruimtebesparing bij het kiezen van BIT via TINYINT wanneer de tabel maar 1 BIT . heeft veld. Gewoon iets om over na te denken.

Een ALTER TABLE doen is een beetje veel voor een grote tafel, zoals je zag. Een optie, hoewel niet de beste, is het toevoegen van een NOT NULL veld--Number_1new --met een DEFAULT waarde (dit zal onmiddellijk zijn vanwege de standaardwaarde, in ieder geval beginnend met SQL 2012) die geen van hen natuurlijk zou hebben (bijv. 255) en vervolgens de waarden langzaam migreren, in een lus, zoals in:

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

En als dat gedaan is, doe dan:

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

Dat kun je natuurlijk het beste in een TRANSACTIE verpakken, en dat verpakt in een TRY/CATCH. Wanneer de gerelateerde code is bijgewerkt en alles is getest en de gegevens er goed uitzien, dan kun je de Number_1old laten vallen kolom.

De beste manier die ik heb gevonden, is echter om een ​​nieuwe tabel te maken, de gegevens langzaam over te zetten en vervolgens de tabellen en de code tegelijkertijd om te wisselen. Ik heb de stappen gedetailleerd beschreven in een artikel over SQL Server Central:Restructure 100 Million Row (of meer) Tafels in seconden. SRSLY! (gratis registratie vereist). Voor het geval er problemen zijn om bij dat artikel te komen, volgen hier de basisstappen:

  1. Maak een nieuwe tabel met de ideale structuur--[tableNew]. Als u Enterprise Edition gebruikt, kunt u overwegen ROW- of PAGE-compressie in te schakelen, omdat deze soms kunnen helpen. Maar doe eerst wat onderzoek, want er zijn situaties waarin ze een negatief effect hebben. Er is documentatie over MSDN om u te helpen erachter te komen, evenals enkele hulpmiddelen om potentiële besparingen in te schatten. Maar zelfs als je compressie inschakelt, zou ik die actie niet zien als vervanging van het project dat je hier aan het doen bent.
  2. Een trigger toevoegen AFTER UPDATE, DELETE op [tabel] om wijzigingen synchroon te houden (maar u hoeft zich geen zorgen te maken over nieuwe rijen)
  3. Maak een SQL Agent-taak die in batches over ontbrekende rijen beweegt. Doe dit in een lus die een INSERT INTO [tableNew] (Columns) SELECT TOP (n) Columns FROM [table] WHERE ?? ORDER BY ??
  4. De WHERE- en ORDER BY-clausules zijn afhankelijk van de situatie. Ze moeten erop gericht zijn om optimaal gebruik te maken van de geclusterde index. Als de geclusterde index van de nieuwe tabel structureel hetzelfde is als de oude/huidige tabel, dan kun je aan het begin van elke lus de MAX([id]) uit [tableNew] halen en deze gebruiken om de WHERE table.[id] > @MaxIdInTableNew ORDER BY table.[id] .
  5. Maak de nieuwe tabel, activeer de huidige tabel en SQL Agent Job ongeveer een week voordat u de volledige omschakeling moet doen. Dat tijdsbestek kan veranderen op basis van uw situatie, maar zorg ervoor dat u uzelf voldoende tijd geeft. Het is veel beter voor de baan om het migreren van rijen af ​​te ronden en er maar een paar tegelijk binnen te laten druppelen, in tegenstelling tot 100k verlegen van de volledige set als de release zou moeten beginnen.
  6. Als het plan is om de andere gerelateerde tabellen te migreren (de PK-verwijzingen voor de twee FK's die u wilt omzetten in INT s), maak dan die velden hier INT nu en voeg de FK pas toe als die andere tabellen zijn gemigreerd naar INT-velden als hun PK's. U wilt deze tabel niet opnieuw moeten opbouwen om die wijziging voor de FK-velden aan te brengen.
  7. Tijdens de cut-over (in een TRY / CATCH natuurlijk):
    1. BEGIN MET TRAN
    2. doe een laatste rijtelling op beide tabellen om er zeker van te zijn dat alles wordt verplaatst (wilt u misschien de rijen voor de release controleren om er zeker van te zijn dat de trigger de updates en verwijderingen heeft uitgevoerd zoals verwacht)
    3. de huidige tabel hernoemen naar "oud"
    4. hernoem de "nieuwe" tabel om de "nieuwe" niet te hebben
    5. laat de SQL Agent-taak vallen (of schakel deze op zijn minst uit)
    6. hernoem en afhankelijke objecten zoals beperkingen, enz.
    7. COMMIT


  1. Hoe krijg ik ForeignCollection Field in Cursor in Ormlite

  2. Uitzondering in hoofdthread org.hibernate.MappingException:onbekende entiteit

  3. mysql wijziging innodb_large_prefix

  4. Hoe InfluxDB te installeren op Ubuntu 20.10