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
IDENTITYfor en kolonne overføres, men ikke hvis:-
SELECTsætningen indeholder sammenføjede tabeller (ved hjælp afJOINellerUNION),GROUPBYklausul 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 enJOINtil 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
IDENTITYer fra en ekstern datakilde
-
- Du kan ikke
SELECT…INTOenten en tabelværdiparameter eller en tabelvariabel som destination, selvom du kan vælgeFROMdem. - 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
ORDERBYklausul, men det ignoreres generelt. På grund af dette er rækkefølgen afIDENTITY_INSERTikke garanteret. - Når en beregnet kolonne er inkluderet i
SELECTliste, 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…INTOblev udført. - Som med en
CREATETABLE-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.