Hvornår skal man bruge SELECT… INTO-sætningen (PE003)
Vi kan bruge SELECT…INTO
i SQL Server til at oprette en ny tabel fra en tabelkilde. SQL Server bruger attributterne for udtrykkene i SELECT
-listen til at definere strukturen i den nye tabel.
Inden SQL Server 2005 skal du bruge SELECT…INTO
i produktionskoden var en ydeevne ‘kodelugt’, fordi den erhvervede skemalåser på systemtabeller i databasen, hvilket fik SQL Server til at virke ikke reagerer, mens forespørgslen blev udført. Dette skyldes, at det er en DDL-sætning i en implicit transaktion, som uundgåeligt er langvarig, da dataene indsættes i den samme SQL-erklæring. Denne adfærd blev dog rettet i SQL Server 2005, da låsemodellen blev ændret.
SELECT…INTO
blev populær, fordi det var en hurtigere måde at indsætte data på end at bruge INSERT
INTO…SELECT…
. Dette skyldtes hovedsageligt, at SELECT…INTO
operationen, hvor det var muligt, var masselogget. Selvom INSERT
INTO
nu kan logges i bulk, ser du muligvis stadig denne ydelsesfordel i SQL Server 2012 og 2014, fordi SELECT…INTO
kan paralleliseres på disse versioner, mens understøttelse af parallelisering af INSERT
INTO
kun opstod i SQL Server 2016. Med SELECT…INTO
har du dog stadig opgaven med at definere alle krævede indekser og begrænsninger osv. På den nye tabel.
En anbefaling til undgå brug af SELECT…INTO
til produktionskode er inkluderet som en kodeanalyseregel i SQL Prompt (PE003).
Oprettelse af tabeller ved hjælp af SELECT INTO-sætningen
Funktionen SELECT…INTO
i SQL Server er designet til at gemme eller ‘vedvare’ en tabelkilde som en del af en proces. Her er et simpelt eksempel:
En tabelkilde kan dog være mange andre ting end en konventionel tabel, såsom en brugerdefineret funktion, en OpenQuery
, en OpenDataSource
, en OPENXML
-sætning, en afledt tabel, en sammenføjet tabel, en drejetabel, en ekstern datakilde, en tabelvariabel eller en variabel funktion. Det er med disse mere eksotiske tabelkilder, at SELECT…INTO
syntaksen bliver mere nyttig.
Er SELECT I en del af ANSI standard?
ANSI-standarderne understøtter en SELECT…INTO
-konstruktion; det kaldes en singleton select, og det indlæser en enkelt række med værdier, men det bruges meget sjældent (tak til Joe Celko for at påpege dette).
Folk bruger ofte SELECT…INTO
med den misforståelse, at det er en hurtig måde at kopiere tabeller på, og det kommer derfor som en overraskelse, at ingen af indekserne, begrænsningerne, de beregnede kolonner eller udløsere defineret i kildetabellen overføres til den nye tabel. De kan heller ikke specificeres i SELECT…INTO
udsagnet. Det gør heller ikke noget ved ugyldighed eller bevarelse af beregnede kolonner. Alle disse opgaver skal udføres med tilbagevirkende kraft med de tilgængelige data, hvilket uundgåeligt tager tid.
Du kan dog bruge funktionen IDENTITY
(datatype, frø, inkrement) for at oprette et identitetsfelt, og det er muligt, når kilden er en enkelt tabel, at oprette en kolonne i destinationstabellen til en identitetskolonne. Det er denne kendsgerning, der sandsynligvis får udviklere til at antage, at den overfører andre kolonneattributter.
Desuden kan den heller ikke oprette partitionerede tabeller, sparsomme kolonner eller andre attributter, der er arvet fra en kildetabel. Hvordan kunne det være, når dataene muligvis kommer fra en forespørgsel, der involverer mange sammenføjninger eller fra en eksotisk ekstern datakilde?
Siden SQL 2012 SP1 CU10 kan SELECT…INTO
udføres parallelt, men siden SQL Server 2016 er Parallel Insert tilladt på den konventionelle INSERT INTO…SELECT
-udtalelse med visse begrænsninger, så enhver ydelsesfordel ved at bruge SELECT
… INTO
er nu temmelig formindsket. INSERT
INTO
-processen kan også fremskyndes, hvis den kan masselogges snarere end fuldt gendannet ved at indstille gendannelsesmodellen til enkel eller masselogget, indsættelse i en tom tabel eller en bunke og indstilling af TABLOCK
tip til tabellen.
Det følgende opsummerer nogle af begrænsningerne og begrænsninger ved brug af SELECT…INTO
.
- Egenskaben
IDENTITY
for en kolonne overføres, men ikke hvis:-
SELECT
sætningen indeholder sammenføjede tabeller (ved hjælp afJOIN
ellerUNION
),GROUP
BY
klausul eller samlet funktion.Hvis du skal undgå, at enIDENTITY
-egenskab overføres til den nye tabel, men har brug for kolonnens værdier, er det værd at tilføje enJOIN
til din tabelkilde under en betingelse, der aldrig er sand, eller enUNION
, der ikke indeholder nogen rækker. -
IDENTITY
-kolonnen er opført mere end én gang iSELECT
-listen -
IDENTITY
-kolonnen er en del af et udtryk - Kolonnen
IDENTITY
er fra en ekstern datakilde
-
- Du kan ikke
SELECT…INTO
enten en tabelværdiparameter eller en tabelvariabel som destination, selvom du kan vælgeFROM
dem. - Selvom din kilde er en opdelt tabel, den nye tabel oprettes i standardfilgruppen. I SQL Server 2017 er det dog muligt at specificere den filgruppe, hvor destinationstabellen oprettes, via
ON
-klausulen. - Du kan angive en
ORDER
BY
klausul, men det ignoreres generelt. På grund af dette er rækkefølgen afIDENTITY_INSERT
ikke garanteret. - Når en beregnet kolonne er inkluderet i
SELECT
liste, er den tilsvarende kolonne i den nye tabel ikke en beregnet kolonne. Værdierne i den nye kolonne er de værdier, der blev beregnet på det tidspunktSELECT…INTO
blev udført. - Som med en
CREATE
TABLE
-erklæring, hvis enSELECT…INTO
-erklæring er indeholdt i en eksplicit transaktion, er den / de underliggende række (r) i de berørte systemtabeller udelukkende låst, indtil transaktionen udtrykkeligt er begået. I mellemtiden vil dette resultere i blokke på andre processer, der bruger disse systemtabeller.
Der er en vis forvirring omkring problemer, der kan opstå med brugen af SELECT…INTO
ved hjælp af midlertidige tabeller. SELECT…INTO
har fået et noget uretfærdigt ry for dette, men det var en del af et mere generelt problem, der involverede latch-stridigheder i tempdb
under tung belastning af oprettelse og sletning af små tempetabeller. Når SELECT…INTO
blev vedtaget med entusiasme, kunne det i høj grad øge denne type aktivitet. Problemet kunne let løses i SQL Server 2000 og fremefter med introduktionen af brugen af sporingsflag TF1118, som ikke længere er påkrævet fra SQL Server 2016 og fremefter. For en fuldstændig forklaring, se Misforståelser omkring TF 1118.
Resume
Sammenfattende er SELECT…INTO
en god måde at lave en tabel- kilde midlertidigt vedvarende som en del af en proces, hvis du ikke er ligeglad med begrænsninger, indekser eller specielle kolonner. Det er ikke en god måde at kopiere en tabel på, fordi kun det tætteste væsentlige i tabelskemaet kan kopieres. I årenes løb har der været faktorer, der har øget eller reduceret tiltrækningen af SELECT…INTO
, men generelt er det en god ide at undgå at bruge det, når det er muligt. Opret i stedet en tabel eksplicit med det fulde udvalg af funktioner, som tabellen har, og som er designet til at sikre, at data er konsistente.