Când se folosește instrucțiunea SELECT … INTO (PE003)
Putem folosi SELECT…INTO
în SQL Server pentru a crea un nou tabel dintr-o sursă de tabel. SQL Server utilizează atributele expresiilor din lista SELECT
pentru a defini structura noii tabele.
Înainte de SQL Server 2005, utilizați SELECT…INTO
în codul de producție a fost un „miros de cod” al performanței, deoarece a dobândit blocaje de schemă pe tabelele de sistem ale bazei de date, determinând SQL Server să nu mai răspundă în timpul executării interogării. Acest lucru se datorează faptului că este o declarație DDL într-o tranzacție implicită, care este inevitabil de lungă durată, deoarece datele sunt inserate în aceeași instrucțiune SQL. Cu toate acestea, acest comportament a fost remediat în SQL Server 2005, când s-a schimbat modelul de blocare.
SELECT…INTO
a devenit popular deoarece era un mod mai rapid de a insera date decât de a utiliza INSERT
INTO…SELECT…
. Acest lucru s-a datorat în principal operațiunii SELECT…INTO
fiind, acolo unde este posibil, înregistrată în bloc. Deși INSERT
INTO
poate fi acum înregistrat în bloc, este posibil să vedeți în continuare acest avantaj de performanță în SQL Server 2012 și 2014, deoarece SELECT…INTO
poate fi paralelizat pe aceste versiuni, în timp ce suportul pentru paralelizarea INSERT
INTO
a apărut doar în SQL Server 2016. Cu toate acestea, cu SELECT…INTO
, aveți în continuare sarcina de a defini toți indicii și constrângerile necesare și așa mai departe, pe noul tabel.
O recomandare pentru evitați utilizarea SELECT…INTO
, pentru codul de producție, este inclusă ca regulă de analiză a codului în SQL Prompt (PE003).
Crearea tabelelor folosind instrucțiunea SELECT INTO
Funcția SELECT…INTO
din SQL Server a fost concepută pentru a stoca sau „persista” o sursă de tabel ca parte a unui proces. Iată un exemplu simplu:
Cu toate acestea, o sursă de tabel poate fi mult mai diferită decât o tabelă convențională, cum ar fi o funcție definită de utilizator, o OpenQuery
, o OpenDataSource
, o clauză OPENXML
, un tabel derivat, un tabel îmbinat, un tabel pivotat, o sursă de date la distanță, o variabilă de tabel sau o funcție variabilă. Cu aceste surse de tabel mai exotice, sintaxa SELECT…INTO
devine mai utilă.
SE SELECTĂ ÎN parte a ANSI standard?
Standardele ANSI acceptă o construcție SELECT…INTO
; se numește singleton select și încarcă un singur rând cu valori, dar este foarte rar folosit (Mulțumim lui Joe Celko pentru că a arătat acest lucru).
Oamenii folosesc adesea SELECT…INTO
cu neînțelegerea faptului că este un mod rapid de copiere a tabelelor și, prin urmare, este o surpriză faptul că niciunul dintre indici, constrângeri, coloane calculate sau declanșatoare definite în tabelul sursă sunt transferate în tabelul nou. Nu pot fi specificate nici în declarația SELECT…INTO
. De asemenea, nu face nimic despre nulitate sau păstrarea coloanelor calculate. Toate aceste sarcini trebuie făcute retrospectiv cu datele existente, ceea ce necesită inevitabil timp.
Puteți, totuși, utiliza funcția IDENTITY
(tip de date, seed, increment) pentru a configura un câmp de identitate și este posibil, când sursa este un singur tabel, să se transforme o coloană a tabelului de destinație într-o coloană de identitate. Acest fapt îi determină probabil pe dezvoltatori să presupună că va transfera alte atribute de coloană.
De asemenea, nu poate crea tabele partiționate, coloane rare sau orice alt atribut moștenit dintr-o tabelă sursă. Cum ar putea fi atunci când datele ar putea proveni dintr-o interogare care implică multe îmbinări sau dintr-o sursă de date externă exotică?
Din SQL 2012 SP1 CU10, SELECT…INTO
să fie executat în paralel, cu toate acestea, de la SQL Server 2016, Parallel Insert a fost permis pe declarația convențională INSERT INTO…SELECT
, cu anumite restricții, deci orice avantaj de performanță al utilizării SELECT
… INTO
este acum destul de diminuat. Procesul INSERT
INTO
poate fi de asemenea accelerat dacă poate fi înregistrat în bloc, mai degrabă decât complet recuperat, prin setarea modelului de recuperare la jurnal simplu sau în bloc, inserarea într-un tabel gol sau o grămadă și setarea TABLOCK
indiciu pentru tabel.
Următorul rezumă câteva dintre restricții și limitări la utilizarea SELECT…INTO
.
- Proprietatea
IDENTITY
a unei coloane este transferată, dar nu dacă:- Instrucțiunea
SELECT
conține tabele unite (utilizând fieJOIN
, fieUNION
),GROUP
BY
clauză sau funcție agregată.Dacă trebuie să evitați ca o proprietateIDENTITY
să fie transferată în noul tabel, dar aveți nevoie de valorile coloanei, merită adăugată oJOIN
către sursa de tabel cu o condiție care nu este niciodată adevărată sau unUNION
care nu oferă niciun rând. -
IDENTITY
coloana este listată de mai multe ori în listaSELECT
- Coloana
IDENTITY
face parte unei expresii - Coloana
IDENTITY
provine dintr-o sursă de date la distanță
- Instrucțiunea
- Nu puteți
SELECT…INTO
fie un parametru cu valoare de tabel, fie o variabilă de tabel ca destinație, deși le puteți selectaFROM
. - Chiar dacă sursa dvs. este un tabel partiționat, noul tabel este creat în grupul de fișiere implicit. Cu toate acestea, în SQL Server 2017, este posibil să specificați grupul de fișiere în care este creat tabelul de destinație, prin clauza
ON
. - Puteți specifica un
ORDER
BY
clauză, dar în general este ignorată. Din acest motiv, ordineaIDENTITY_INSERT
nu este garantată. - Când o coloană calculată este inclusă în
SELECT
listă, coloana corespunzătoare din noul tabel nu este o coloană calculată. Valorile din noua coloană sunt valorile care au fost calculate la momentul executăriiSELECT…INTO
. - La fel ca în cazul unui
CREATE
TABLE
declarație, dacă o instrucțiuneSELECT…INTO
este conținută într-o tranzacție explicită, rândul (ele) subiacent (e) în tabelele de sistem afectate sunt blocat exclusiv până când tranzacția este angajată în mod explicit. Între timp, acest lucru va duce la blocări ale altor procese care utilizează aceste tabele de sistem.
Există o oarecare confuzie cu privire la problemele care pot apărea cu utilizarea SELECT…INTO
folosind tabele temporare. SELECT…INTO
și-a câștigat o reputație oarecum nedreaptă pentru acest lucru, dar a făcut parte dintr-o problemă mai generală care implică disputa de blocare în tempdb
sub o încărcătură mare de crearea și ștergerea tabelelor temporare mici. Când SELECT…INTO
a fost adoptat cu entuziasm, ar putea crește foarte mult acest tip de activitate. Problema ar putea fi rezolvată cu ușurință în SQL Server 2000 și ulterior odată cu introducerea utilizării semnalizatorului de urmărire TF1118, care nu mai este necesară începând cu SQL Server 2016. Pentru o explicație completă, consultați concepții greșite despre TF 1118.
Rezumat
În rezumat, SELECT…INTO
este un mod bun de a crea un tabel- sursă temporar persistentă ca parte a unui proces, dacă nu vă pasă de constrângeri, indici sau coloane speciale. Nu este o modalitate bună de a copia un tabel, deoarece numai cele mai simple elemente esențiale ale schemei tabelului pot fi copiate. De-a lungul anilor, au existat factori care au crescut sau au scăzut atracția SELECT…INTO
, dar, în general, este o idee bună să evitați utilizarea acestuia ori de câte ori este posibil. În schimb, creați un tabel în mod explicit, cu întreaga gamă de caracteristici pe care le are tabelul, concepute pentru a se asigura că datele sunt coerente.