sql >> Database >  >> RDS >> Sqlserver

Nieuwe kolomwijzigingen met alleen metagegevens in SQL Server 2016

De ALTER TABLE ... ALTER COLUMN commando is zeer krachtig. U kunt het gebruiken om het gegevenstype, de lengte, de precisie, de schaal, de nullabiliteit, de sortering... en vele andere dingen van een kolom te wijzigen.

Het is zeker handiger dan het alternatief:een nieuwe tabel maken en de gegevens migreren telkens wanneer een wijziging nodig is. Toch is er maar zoveel dat kan worden gedaan om de onderliggende complexiteit te verbergen. Naast een groot aantal beperkingen op wat zelfs mogelijk is met dit commando, is er altijd de kwestie van de prestaties.

Uiteindelijk worden tabellen opgeslagen als een reeks bytes met wat metadata elders in het systeem om te beschrijven wat elk van die bytes betekent en hoe ze zich verhouden tot elk van de verschillende kolommen van de tabel. Wanneer we SQL Server vragen om een ​​bepaald aspect van de definitie van een kolom te wijzigen, moet het controleren of de bestaande gegevens compatibel zijn met de nieuwe definitie. Het moet ook bepalen of de huidige fysieke lay-out moet worden gewijzigd.

Afhankelijk van het type wijziging en de configuratie van de database, een ALTER COLUMN commando moet een van de volgende acties uitvoeren:

  1. Wijzig metadata alleen in systeemtabellen.
  2. Controleer alle bestaande gegevens op compatibiliteit en wijzig vervolgens de metagegevens.
  3. Herschrijf enkele of alle opgeslagen gegevens zodat ze overeenkomen met de nieuwe definitie.

Optie 1 vertegenwoordigt het ideale geval vanuit prestatieoogpunt. Het vereist slechts een paar wijzigingen in systeemtabellen en een minimale hoeveelheid logboekregistratie. De bewerking vereist nog steeds een beperkende schemawijziging Sch-M lock, maar de metadata-wijzigingen zelf zullen zeer snel worden voltooid, ongeacht de grootte van de tabel.

Alleen metadata-wijzigingen

Er zijn een aantal speciale gevallen waar u op moet letten, maar als algemene samenvatting vereisen de volgende acties alleen wijzigingen in metadata:

  • Van NOT NULL naar NULL voor hetzelfde gegevenstype.
  • De maximale grootte van een varchar vergroten , nvarchar , of varbinary kolom (behalve tot max ).

Verbeteringen in SQL Server 2016

Het onderwerp van dit bericht zijn de aanvullende wijzigingen die zijn ingeschakeld voor alleen metadata vanaf SQL Server 2016 . Er zijn geen wijzigingen in de syntaxis nodig en er hoeven geen configuratie-instellingen te worden gewijzigd. U krijgt deze ongedocumenteerde verbeteringen gratis.

De nieuwe mogelijkheden zijn gericht op een subset van de vaste lengte gegevens typen. De nieuwe mogelijkheden zijn van toepassing op row-store tabellen in de volgende omstandigheden:

  • Compressie moet zijn ingeschakeld:
    • Op alle indexen en partities , inclusief de base heap of geclusterde index.
    • Ofwel ROW of PAGE compressie.
    • Indexen en partities kunnen een mengsel gebruiken van deze compressieniveaus. Het belangrijkste is dat er geen ongecomprimeerde indexen of partities zijn.
  • Veranderen van NULL naar NOT NULL is niet toegestaan .
  • De volgende gehele typewijzigingen worden ondersteund:
    • smallint naar integer of bigint .
    • integer naar bigint .
    • smallmoney naar money (gebruikt interne representatie van gehele getallen).
  • De volgende tekenreeksen en binaire typen veranderen worden ondersteund:
    • char(n) naar char(m) of varchar(m)
    • nchar(n) naar nchar(m) of nvarchar(m)
    • binary(n) naar binary(m) of varbinary(m)
    • Al het bovenstaande alleen voor n < m en m != max
    • Verzamelingswijzigingen zijn niet toegestaan

Deze wijzigingen kunnen alleen metagegevens zijn omdat de onderliggende binaire gegevenslay-out niet verandert wanneer Kolombeschrijving rijformaat wordt gebruikt (vandaar de noodzaak van compressie). Zonder compressie gebruikt rijopslag de originele FixedVar weergave, die deze gegevenstypewijzigingen met een vaste lengte niet kan accommoderen zonder de fysieke lay-out te herschrijven.

Je merkt misschien dat tinyint wordt weggelaten uit de lijst met integertypes. Dit komt omdat het niet-ondertekend is, terwijl de andere typen gehele getallen allemaal ondertekend zijn, dus een wijziging met alleen metagegevens is niet mogelijk. Een waarde van 255 past bijvoorbeeld in één byte voor tinyint , maar vereist twee bytes in een van de ondertekende formaten. De ondertekende formaten kunnen -128 tot +127 in één byte bevatten wanneer ze zijn gecomprimeerd.

Integer-voorbeeld

Een zeer handige toepassing van deze verbetering is het wijzigen van het gegevenstype van een kolom met de IDENTITY eigendom.

Stel dat we de volgende heaptabel hebben met rijcompressie (paginacompressie zou ook werken):

DROP TABLE IF EXISTS dbo.Test;
GO
CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL,
    some_value integer NOT NULL
)
WITH (DATA_COMPRESSION = ROW);

Laten we 5 miljoen rijen gegevens toevoegen. Dit is voldoende om duidelijk te maken (vanuit het oogpunt van prestaties) of het wijzigen van het kolomgegevenstype een bewerking is die alleen metadata is of niet:

WITH Numbers AS
(
    SELECT 
        n = ROW_NUMBER() OVER (ORDER BY @@SPID) 
    FROM sys.all_columns AS AC1
    CROSS JOIN sys.all_columns AS AC2
    ORDER BY n
    OFFSET 0 ROWS
    FETCH FIRST 5 * 1000 * 1000 ROWS ONLY
)
INSERT dbo.Test
    WITH (TABLOCKX)
(
    some_value
)
SELECT
    N.n
FROM Numbers AS N;

Vervolgens zullen we de IDENTITY . opnieuw plaatsen om het te laten lijken alsof we bijna geen waarden meer hebben die in een integer passen :

DBCC CHECKIDENT
(
    N'dbo.Test',
    RESEED,
    2147483646
);

We kunnen nog een rij met succes toevoegen:

INSERT dbo.Test
    (some_value)
VALUES
    (123456);

Maar proberen om nog een rij toe te voegen:

INSERT dbo.Test
    (some_value)
VALUES
    (7890);

Resulteert in een foutmelding:

Msg 8115, Level 16, State 1, Line 1
Rekenkundige overloopfout bij het converteren van IDENTITY naar gegevenstype int.

We kunnen dat oplossen door de kolom te converteren naar bigint :

ALTER TABLE dbo.Test
ALTER COLUMN id bigint NOT NULL;

Dankzij de verbeteringen in SQL Server 2016 verandert deze opdracht alleen metadata , en wordt onmiddellijk voltooid. De vorige INSERT instructie (degene die de rekenkundige overloopfout veroorzaakte) is nu succesvol voltooid.

Deze nieuwe mogelijkheid lost niet alle problemen op rond het wijzigen van het type kolom met de IDENTITY eigendom. We zullen nog steeds indexen in de kolom moeten verwijderen en opnieuw moeten maken, eventuele refererende externe sleutels opnieuw moeten maken, enzovoort. Dat valt een beetje buiten het bestek van dit bericht (hoewel Aaron Bertrand er al eerder over heeft geschreven). In staat zijn om het type te wijzigen als een bewerking met alleen metadata doet zeker geen pijn. Met een zorgvuldige planning kunnen de overige benodigde stappen zo efficiënt mogelijk worden uitgevoerd, bijvoorbeeld met minimaal gelogde of ONLINE operaties.

Wees voorzichtig met syntax

Zorg ervoor dat u altijd specificeer NULL of NOT NULL bij het wijzigen van gegevenstypen met ALTER COLUMN . Stel dat we bijvoorbeeld ook het gegevenstype van de some_value . willen wijzigen kolom in onze testtabel van integer NOT NULL naar bigint NOT NULL .

Wanneer we de opdracht schrijven, laten we de NULL . weg of NOT NULL kwalificatie:

ALTER TABLE dbo.Test
ALTER COLUMN some_value bigint;

Deze opdracht wordt met succes voltooid als een wijziging met alleen metagegevens, maar verwijdert ook de NOT NULL beperking. De kolom is nu bigint NULL , dat is niet wat we bedoelden. Dit gedrag is gedocumenteerd, maar het is gemakkelijk over het hoofd te zien.

We kunnen proberen onze fout te herstellen met:

ALTER TABLE dbo.Test
ALTER COLUMN some_value bigint NOT NULL;

Dit is niet een metadata-only wijziging. We mogen niet wijzigen van NULL naar NOT NULL (verwijs terug naar de eerdere tabel als u een opfrissing van de voorwaarden nodig heeft). SQL Server moet alle bestaande waarden controleren om er zeker van te zijn dat er geen nulls aanwezig zijn. Het zal dan fysiek elke rij herschrijven van de tafel. Deze acties zijn niet alleen traag, maar genereren ook veel transactielogboeken, wat een domino-effect kan hebben.

Even terzijde:dezelfde fout is niet mogelijk voor kolommen met de IDENTITY eigendom. Als we een ALTER COLUMN . schrijven statement zonder NULL of NOT NULL in dat geval gaat de engine ervan uit dat we NOT NULL bedoelden omdat de identiteitseigenschap niet is toegestaan ​​op nullable-kolommen. Het is nog steeds een goed idee om niet op dit gedrag te vertrouwen.

Specificeer altijd NULL of NOT NULL met ALTER COLUMN .

Collatie

Bijzondere zorg is nodig bij het wijzigen van een stringkolom die een sortering heeft die niet overeenkomt met de standaard voor de database.

Stel dat we bijvoorbeeld een tabel hebben met een hoofdletter- en accentgevoelige sortering (ervan uitgaande dat de databasestandaard anders is):

DROP TABLE IF EXISTS dbo.Test2;
GO
CREATE TABLE dbo.Test2
(
    id integer IDENTITY NOT NULL,
    some_string char(8) COLLATE Latin1_General_100_CS_AS NOT NULL
)
WITH (DATA_COMPRESSION = ROW);

Voeg 5 miljoen rijen gegevens toe:

WITH Numbers AS
(
    SELECT 
        n = ROW_NUMBER() OVER (ORDER BY @@SPID) 
    FROM sys.all_columns AS AC1
    CROSS JOIN sys.all_columns AS AC2
    ORDER BY n
    OFFSET 0 ROWS
    FETCH FIRST 5 * 1000 * 1000 ROWS ONLY
)
INSERT dbo.Test2
    WITH (TABLOCKX)
(
    some_string
)
SELECT
    CONVERT(char(8), N.n) COLLATE Latin1_General_100_CS_AS
FROM Numbers AS N;

Verdubbel de lengte van de stringkolom met het volgende commando:

ALTER TABLE dbo.Test2
ALTER COLUMN some_string char(16) NOT NULL;

We hebben niet vergeten om NOT NULL op te geven , maar vergat de niet-standaard sortering. SQL Server gaat ervan uit dat we de sortering wilden wijzigen in de standaarddatabase (Latin1_General_CI_AS voor mijn testdatabase). Door de sortering te wijzigen, wordt voorkomen dat de bewerking alleen metagegevens is, en dus duurt de bewerking enkele minuten, waardoor er stapels logboeken worden gegenereerd.

Maak de tabel en gegevens opnieuw met het vorige script en probeer vervolgens de ALTER COLUMN commando opnieuw, maar specificeer de bestaande niet-standaard sortering als onderdeel van het commando:

ALTER TABLE dbo.Test2
ALTER COLUMN some_string 
    char(16) COLLATE Latin1_General_100_CS_AS NOT NULL;

De wijziging wordt nu onmiddellijk voltooid, als een bewerking met alleen metagegevens. Net als bij de NULL en NOT NULL syntaxis, loont het om expliciet te zijn om ongelukken te voorkomen. Dit is in het algemeen een goed advies, niet alleen voor ALTER COLUMN .

Compressie

Houd er rekening mee dat compressie expliciet moet worden gespecificeerd voor elke index, en afzonderlijk voor de basistabel als het een heap is. Dit is een ander voorbeeld waarbij het gebruik van verkorte syntaxis of snelkoppelingen het gewenste resultaat kan voorkomen.

De volgende tabel specificeert bijvoorbeeld geen expliciete compressie voor de primaire sleutel of de in-line indexdefinitie:

CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL PRIMARY KEY,
    some_value integer NOT NULL
        INDEX [IX dbo.Test some_value]
)
WITH (DATA_COMPRESSION = PAGE);

De PRIMARY KEY krijgt een naam toegewezen, standaard CLUSTERED ,en wees PAGE gecomprimeerd. De in-line index is NONCLUSTERED en helemaal niet gecomprimeerd. Deze tabel wordt voor geen van de nieuwe optimalisaties ingeschakeld omdat niet alle indexen en partities zijn gecomprimeerd.

Een veel betere en meer expliciete tabeldefinitie zou zijn:

CREATE TABLE dbo.Test
(
    id integer IDENTITY NOT NULL
        CONSTRAINT [PK dbo.Test id]
        PRIMARY KEY CLUSTERED
        WITH (DATA_COMPRESSION = PAGE),
    some_value integer NOT NULL
        INDEX [IX dbo.Test some_value]
        NONCLUSTERED
        WITH (DATA_COMPRESSION = ROW)        
);

Deze tabel komt in aanmerking voor de nieuwe optimalisaties omdat alle indexen en partities zijn gecomprimeerd. Zoals eerder opgemerkt, is het mengen van compressietypen prima.

Er zijn verschillende manieren om deze CREATE TABLE te schrijven verklaring op een expliciete manier, dus er is een element van persoonlijke voorkeur. Het belangrijke afhaalpunt is om altijd expliciet te zijn over wat je wilt. Dit geldt voor afzonderlijke CREATE INDEX ook verklaringen.

Uitgebreide gebeurtenissen en traceervlag

Er is een uitgebreid evenement speciaal voor de nieuwe metadata-only ALTER COLUMN bewerkingen ondersteund in SQL Server 2016 en later.

De uitgebreide gebeurtenis is compressed_alter_column_is_md_only in de Debug kanaal. De gebeurtenisvelden zijn object_id , column_id , en is_md_only (waar/onwaar).

Deze gebeurtenis geeft alleen aan of een bewerking alleen metagegevens is vanwege de nieuwe mogelijkheden van SQL Server 2016. Kolomwijzigingen die vóór 2016 alleen metagegevens waren, tonen is_md_only = false ondanks dat het nog steeds alleen metadata is.

Andere uitgebreide gebeurtenissen die nuttig zijn voor het bijhouden van ALTER COLUMN bewerkingen omvatten metadata_ddl_alter_column en alter_column_event , beide in de Analytische kanaal.

Moet u uitschakelen de nieuwe SQL Server 2016-mogelijkheden om welke reden dan ook, ongedocumenteerde globale (of start-up) traceringsvlag 3618 kan worden gebruikt. Deze traceringsvlag is niet effectief bij gebruik op sessieniveau. Er is geen manier om een ​​traceervlag op queryniveau op te geven met een ALTER COLUMN commando.

Laatste gedachten

Het is een zeer welkome productverbetering om sommige integer-gegevenstypen met een vaste lengte te kunnen wijzigen met een wijziging met alleen metadata. Het vereist wel dat de tafel al volledig is gecomprimeerd, maar dat wordt hoe dan ook steeds gebruikelijker. Dit geldt met name omdat compressie was ingeschakeld in alle edities vanaf SQL Server 2016 Service Pack 1.

Kolomreeksen van het type string met een vaste lengte komen waarschijnlijk veel minder vaak voor. Een deel hiervan kan te wijten zijn aan enigszins verouderde overwegingen, zoals ruimtegebruik. Wanneer gecomprimeerde stringkolommen met een vaste lengte geen volgspaties opslaan, zijn ze vanuit het oogpunt van opslag net zo efficiënt als stringkolommen met variabele lengte. Het kan vervelend zijn om spaties bij te snijden voor manipulatie of weergave, maar als de gegevens meestal het grootste deel van de maximale lengte in beslag nemen, kunnen typen met een vaste lengte belangrijke voordelen hebben, niet in de laatste plaats met betrekking tot geheugentoekenningen voor zaken als sorteren en hashen.

Het is niet allemaal goed nieuws met compressie ingeschakeld. Ik heb eerder vermeld dat SQL Server soms een wijziging met alleen metagegevens kan uitvoeren nadat is gecontroleerd of alle bestaande waarden met succes naar het nieuwe type worden geconverteerd. Dit is het geval bij gebruik van ALTER COLUMN om te veranderen van integer naar smallint bijvoorbeeld. Helaas zijn deze bewerkingen momenteel niet alleen metadata voor gecomprimeerde objecten.

Erkenningen

Speciale dank aan Panagiotis Antonopoulos (Principal Software Engineer) en Mirek Sztajno (Senior Program Manager) van het SQL Server-productteam voor hun hulp en begeleiding tijdens het onderzoek en het schrijven van dit artikel.

Geen van de details die in dit werk worden gegeven, mogen worden beschouwd als officiële Microsoft-documentatie of productverklaringen.


  1. Moet de scalaire variabele declareren

  2. Retourrijen die numerieke waarden bevatten in Oracle

  3. MariaDB Cluster offline installatie voor CentOS

  4. Rangschikkingsfuncties in SQL Server