När ska vi använda SELECT… INTO-satsen (PE003)
Vi kan använda SELECT…INTO
i SQL Server för att skapa en ny tabell från en tabellkälla. SQL Server använder attributen för uttrycken i SELECT
-listan för att definiera strukturen för den nya tabellen.
Innan SQL Server 2005 används SELECT…INTO
i produktionskoden var en prestanda ’kodlukt’ eftersom den förvärvade schemalås på systemtabeller i databasen, vilket fick SQL Server att inte svara när frågan kördes. Detta beror på att det är ett DDL-uttalande i en implicit transaktion, som oundvikligen är långvarig eftersom data infogas i samma SQL-uttalande. Detta beteende fixades dock i SQL Server 2005 när låsmodellen ändrades.
SELECT…INTO
blev populär eftersom det var ett snabbare sätt att infoga data än att använda INSERT
INTO…SELECT…
. Detta berodde främst på att SELECT…INTO
-operationen, om möjligt, var massloggad. Även om INSERT
INTO
nu kan massloggas kan du fortfarande se denna prestandafördel i SQL Server 2012 och 2014, eftersom SELECT…INTO
kan parallelliseras i dessa versioner, medan stöd för parallellisering av INSERT
INTO
bara uppstod i SQL Server 2016. Men med SELECT…INTO
har du fortfarande uppgiften att definiera alla nödvändiga index och begränsningar och så vidare i den nya tabellen.
En rekommendation till undvik användning av SELECT…INTO
, för produktionskod, ingår som en kodanalysregel i SQL Prompt (PE003).
Skapa tabeller med SELECT INTO-satsen
Funktionen SELECT…INTO
i SQL Server utformades för att lagra eller ’bestå’ en tabellkälla som en del av en process. Här är ett enkelt exempel:
En tabellkälla kan dock vara många andra saker än en konventionell tabell, till exempel en användardefinierad funktion, en OpenQuery
, en OpenDataSource
, en OPENXML
-sats, en härledd tabell, en sammanfogad tabell, en svängbar tabell, en fjärrdatakälla, en tabellvariabel eller en variabel funktion. Det är med dessa mer exotiska tabellkällor som SELECT…INTO
syntaxen blir mer användbar.
Är VÄLJ I EN del av ANSI standard?
ANSI-standarderna stöder en SELECT…INTO
-konstruktion; den kallas en singleton select och den laddar en rad med värden, men den används mycket sällan (tack till Joe Celko för att han påpekade detta).
Människor använder ofta SELECT…INTO
med missförståndet att det är ett snabbt sätt att kopiera tabeller, och det är därför en överraskning att inget av index, begränsningar, beräknade kolumner eller triggers definierade i källtabellen överförs till den nya tabellen. De kan inte anges i uttalandet SELECT…INTO
. Det gör inte heller något om ogiltighet eller att bevara beräknade kolumner. Alla dessa uppgifter måste göras i efterhand med data på plats, vilket oundvikligen tar tid.
Du kan dock använda funktionen IDENTITY
(datatyp, utsäde, inkrement) för att ställa in ett identitetsfält, och det är möjligt, när källan är en enda tabell, att göra en kolumn i måltabellen till en identitetskolumn. Det är detta som förmodligen får utvecklare att anta att det kommer att överföra andra kolumnattribut.
Dessutom kan det inte heller skapa partitionerade tabeller, glesa kolumner eller något annat attribut som ärvs från en källtabell. Hur kan det vara när data kan komma från en fråga som involverar många kopplingar eller från någon exotisk extern datakälla?
Sedan SQL 2012 SP1 CU10 kan SELECT…INTO
köras parallellt, men sedan SQL Server 2016 har Parallel Insert tillåtits på det konventionella INSERT INTO…SELECT
-utdraget, med vissa begränsningar, så alla prestandafördelar med att använda SELECT
… INTO
är nu ganska minskat. INSERT
INTO
-processen kan också påskyndas om den kan massloggas snarare än helt återställas genom att ställa in återställningsmodellen för enkel eller bulkloggad, infoga i en tom tabell eller en hög och ställa in TABLOCK
tips för tabellen.
Följande sammanfattar några av begränsningarna och begränsningar när du använder SELECT…INTO
.
-
IDENTITY
-egenskapen för en kolumn överförs, men inte om:- Uttrycket
SELECT
innehåller sammanfogade tabeller (använder antingenJOIN
ellerUNION
),GROUP
BY
sats eller samlad funktion.Om du behöver undvika att enIDENTITY
-egenskap överförs till den nya tabellen, men behöver kolumnens värden, är det värt att lägga till enJOIN
till din tabellkälla på ett villkor som aldrig är sant, eller enUNION
som inte ger några rader. -
IDENTITY
-kolumnen listas mer än en gång iSELECT
-listan -
IDENTITY
-kolumnen är en del för ett uttryck - Kolumnen
IDENTITY
kommer från en fjärrdatakälla
- Uttrycket
- Du kan inte
SELECT…INTO
antingen en tabellvärderad parameter eller en tabellvariabel som destination, men du kan väljaFROM
dem. - Även om din källa är en partitionerad tabell, den nya tabellen skapas i standardfilgruppen. I SQL Server 2017 är det dock möjligt att ange den filgrupp där måltabellen skapas, via
ON
-satsen. - Du kan ange en
ORDER
BY
klausul, men den ignoreras vanligtvis. På grund av detta garanteras inte ordningen påIDENTITY_INSERT
. - När en beräknad kolumn ingår i
SELECT
listan, motsvarande kolumn i den nya tabellen är inte en beräknad kolumn. Värdena i den nya kolumnen är de värden som beräknades vid tidenSELECT…INTO
kördes. - Som med en
CREATE
TABLE
uttalande, om ettSELECT…INTO
uttalande ingår i en uttrycklig transaktion, är de underliggande raderna i de berörda systemtabellerna uteslutande låst tills transaktionen uttryckligen har begåtts. Under tiden kommer detta att resultera i blockering av andra processer som använder dessa systemtabeller.
Det finns viss förvirring om problem som kan hända med användningen av SELECT…INTO
med hjälp av tillfälliga tabeller. SELECT…INTO
har fått ett något orättvist rykte för detta, men det var en del av ett mer generellt problem med spärrstrid i tempdb
under tung belastning av små temp tabell skapande och radering. När SELECT…INTO
antogs med entusiasm skulle det kunna öka denna typ av aktivitet kraftigt. Problemet kan enkelt lösas i SQL Server 2000 och framåt med introduktionen av spårningsflaggan TF1118, vilket inte längre krävs från SQL Server 2016 och framåt. För en fullständig förklaring, se Missuppfattningar kring TF 1118.
Sammanfattning
Sammanfattningsvis är SELECT…INTO
ett bra sätt att skapa en tabell- källa tillfälligt ihållande som en del av en process, om du inte bryr dig om begränsningar, index eller speciella kolumner. Det är inte ett bra sätt att kopiera en tabell eftersom endast de viktigaste sakerna i tabellschemat kan kopieras. Under åren har det funnits faktorer som har ökat eller minskat attraktionen för SELECT…INTO
, men totalt sett är det en bra idé att undvika att använda det när det är möjligt. Skapa istället en tabell uttryckligen, med hela utbudet av funktioner som tabellen har som är utformade för att säkerställa att data är konsekventa.