Kiedy używać instrukcji SELECT… INTO (PE003)
Możemy użyć SELECT…INTO
w SQL Server, aby utworzyć nową tabelę ze źródła tabeli. SQL Server używa atrybutów wyrażeń z listy SELECT
do zdefiniowania struktury nowej tabeli.
Przed SQL Server 2005 używano SELECT…INTO
w kodzie produkcyjnym występował „zapach kodu” wydajności, ponieważ uzyskał blokady schematu w tabelach systemowych bazy danych, powodując, że SQL Server nie odpowiadał podczas wykonywania zapytania. Dzieje się tak, ponieważ jest to instrukcja DDL w niejawnej transakcji, która jest nieuchronnie długotrwała, ponieważ dane są wstawiane w tej samej instrukcji SQL. Jednak to zachowanie zostało naprawione w SQL Server 2005, kiedy zmienił się model blokowania.
SELECT…INTO
stał się popularny, ponieważ był szybszym sposobem wstawiania danych niż użycie INSERT
INTO…SELECT…
. Było to głównie spowodowane tym, że operacja SELECT…INTO
była, w miarę możliwości, logowana zbiorczo. Chociaż INSERT
INTO
można teraz rejestrować zbiorczo, nadal możesz zauważyć tę przewagę w wydajności w SQL Server 2012 i 2014, ponieważ SELECT…INTO
może być zrównoleglony w tych wersjach, podczas gdy obsługa równoległości INSERT
INTO
pojawiła się tylko w SQL Server 2016. Jednak w przypadku SELECT…INTO
nadal masz zadanie zdefiniowania wszystkich wymaganych indeksów i ograniczeń itd. W nowej tabeli.
Zalecenie, aby unikaj używania SELECT…INTO
, dla kodu produkcyjnego, jest zawarta jako reguła analizy kodu w SQL Prompt (PE003).
Tworzenie tabel przy użyciu instrukcji SELECT INTO
Funkcja SELECT…INTO
w SQL Server została zaprojektowana w celu przechowywania lub „utrwalania” źródła tabeli jako części procesu. Oto prosty przykład:
Jednak źródłem tabeli może być wiele innych rzeczy niż konwencjonalna tabela, na przykład funkcja zdefiniowana przez użytkownika, OpenQuery
, OpenDataSource
, klauzula OPENXML
, tabela pochodna, tabela połączona, tabela przestawna, zdalne źródło danych, zmienna tabeli lub zmienna funkcja. Dzięki tym bardziej egzotycznym źródłom tabel składnia SELECT…INTO
staje się bardziej użyteczna.
Czy SELECT INTO jest częścią ANSI standard?
Standardy ANSI obsługują konstrukcję SELECT…INTO
; nazywa się to pojedynczym wyborem i ładuje pojedynczy wiersz z wartościami, ale jest bardzo rzadko używany (dzięki Joe Celko za wskazanie tego).
Ludzie często używają SELECT…INTO
z nieporozumieniem, że jest to szybki sposób kopiowania tabel, więc zaskakuje fakt, że żaden z indeksów, ograniczeń, kolumn obliczeniowych ani wyzwalaczy zdefiniowanych w tabela źródłowa zostanie przeniesiona do nowej tabeli. Nie można ich również określić w instrukcji SELECT…INTO
. Nie robi również nic w zakresie dopuszczalności wartości null ani zachowywania kolumn obliczonych. Wszystkie te zadania muszą być wykonywane retrospektywnie z danymi na miejscu, co nieuchronnie wymaga czasu.
Możesz jednak użyć funkcji IDENTITY
(typ danych, seed, inkrementacja) w celu skonfigurowania pola tożsamości, a gdy źródłem jest pojedyncza tabela, można przekształcić kolumnę tabeli docelowej w kolumnę tożsamości. Jest to fakt, który prawdopodobnie prowadzi programistów do założenia, że przeniesie inne atrybuty kolumn.
Ponadto nie może również tworzyć tabel podzielonych na partycje, rzadkich kolumn ani żadnych innych atrybutów dziedziczonych z tabeli źródłowej. Jak to możliwe, skoro dane mogą pochodzić z zapytania zawierającego wiele złączeń lub z jakiegoś egzotycznego zewnętrznego źródła danych?
Od wersji CU10 dodatku SQL 2012 SP1, SELECT…INTO
może być wykonywane równolegle, jednak od wersji SQL Server 2016 funkcja Parallel Insert jest dozwolona w konwencjonalnej instrukcji INSERT INTO…SELECT
, z pewnymi ograniczeniami, więc każda korzyść z korzystania z SELECT
… INTO
jest teraz raczej zmniejszona. Proces INSERT
INTO
można również przyspieszyć, jeśli można go zapisać zbiorczo zamiast całkowicie odzyskać, ustawiając model odzyskiwania do prostego lub zbiorczego logowania, wstawiania do pustej tabeli lub stosu i ustawiania TABLOCK
wskazówki dotyczącej tabeli.
Poniżej podsumowano niektóre ograniczenia i ograniczenia podczas korzystania z SELECT…INTO
.
- Właściwość
IDENTITY
kolumny jest przenoszona, ale nie, jeśli:- Instrukcja
SELECT
zawiera połączone tabele (przy użyciuJOIN
lubUNION
),GROUP
BY
klauzula lub funkcja agregująca.Jeśli chcesz uniknąć przeniesienia właściwościIDENTITY
do nowej tabeli, ale potrzebujesz wartości z kolumny, warto dodaćJOIN
do źródła tabeli pod warunkiem, który nigdy nie jest prawdziwy, lubUNION
, który nie zawiera żadnych wierszy. -
IDENTITY
jest wymieniony więcej niż jeden raz na liścieSELECT
- Kolumna
IDENTITY
jest częścią wyrażenia - Kolumna
IDENTITY
pochodzi ze zdalnego źródła danych
- Instrukcja
- Nie możesz
SELECT…INTO
parametr wyceniony w tabeli lub zmienną tabeli jako miejsce docelowe, chociaż możesz wybrać jeFROM
. - Nawet jeśli Twoje źródło jest tabelą podzieloną na partycje, nowa tabela jest tworzona w domyślnej grupie plików. Jednak w SQL Server 2017 można określić grupę plików, w której tworzona jest tabela docelowa, za pomocą klauzuli
ON
. - Możesz określić
ORDER
BY
, ale zazwyczaj jest ignorowana. Z tego powodu kolejnośćIDENTITY_INSERT
nie jest gwarantowana. - Gdy kolumna obliczeniowa jest uwzględniona w
SELECT
lista, odpowiednia kolumna w nowej tabeli nie jest kolumną obliczeniową. Wartości w nowej kolumnie to wartości obliczone w momencie wykonaniaSELECT…INTO
. - Tak jak w przypadku
CREATE
TABLE
, jeśli instrukcjaSELECT…INTO
jest zawarta w jawnej transakcji, podstawowe wiersze w odpowiednich tabelach systemowych są zablokowane na wyłączność do momentu wyraźnego zatwierdzenia transakcji. W międzyczasie spowoduje to blokowanie innych procesów, które używają tych tabel systemowych.
Istnieje pewne zamieszanie dotyczące problemów, które mogą wystąpić podczas korzystania z SELECT…INTO
przy użyciu tabel tymczasowych. SELECT…INTO
zyskał w związku z tym nieco niesprawiedliwą reputację, ale było to częścią bardziej ogólnego problemu związanego z rywalizacją o zatrzask w tempdb
pod dużym obciążeniem tworzenia i usuwania małych tabel tymczasowych. Kiedy SELECT…INTO
został przyjęty z entuzjazmem, może znacznie zwiększyć ten rodzaj aktywności. Problem można było łatwo rozwiązać w SQL Server 2000 i nowszych, wprowadzając użycie flagi śledzenia TF1118, która nie jest już wymagana od SQL Server 2016. Aby uzyskać pełne wyjaśnienie, zobacz Nieporozumienia wokół TF 1118.
Podsumowanie
Podsumowując, SELECT…INTO
to dobry sposób na zrobienie tabeli- źródło jest tymczasowo trwałe jako część procesu, jeśli nie dbasz o ograniczenia, indeksy lub specjalne kolumny. Nie jest to dobry sposób kopiowania tabeli, ponieważ można skopiować tylko podstawowe elementy schematu tabeli. Z biegiem lat istniały czynniki, które zwiększały lub zmniejszały atrakcyjność SELECT…INTO
, ale ogólnie rzecz biorąc, dobrze jest unikać jej używania, gdy tylko jest to możliwe. Zamiast tego utwórz tabelę jawnie, z pełnym zakresem funkcji, które posiada tabela, które mają zapewnić spójność danych.