Kdy použít příkaz SELECT… INTO (PE003)
Můžeme použít SELECT…INTO
na serveru SQL Server k vytvoření nové tabulky ze zdroje tabulky. SQL Server používá k definování struktury nové tabulky atributy výrazů v seznamu SELECT
.
Před SQL Server 2005 bylo použití SELECT…INTO
v produkčním kódu byl výkon ‚vůně kódu‘, protože získal zámky schémat v systémových tabulkách databáze, což způsobilo, že SQL Server při provádění dotazu nereagoval. Je to proto, že se jedná o příkaz DDL v implicitní transakci, která je nevyhnutelně dlouhotrvající, protože data jsou vložena do stejného příkazu SQL. Toto chování však bylo opraveno na serveru SQL Server 2005, když se změnil zamykací model.
SELECT…INTO
se stal populárním, protože to byl rychlejší způsob vkládání dat než použití INSERT
INTO…SELECT…
. Důvodem bylo hlavně to, že operace SELECT…INTO
byla, pokud je to možné, hromadně protokolována. Ačkoli INSERT
INTO
lze nyní hromadně protokolovat, můžete tuto výhodu výkonu v SQL Server 2012 a 2014 stále vidět, protože SELECT…INTO
lze u těchto verzí paralelizovat, zatímco podpora pro paralelizaci INSERT
INTO
se objevila pouze na serveru SQL Server 2016. U SELECT…INTO
však stále máte za úkol definovat všechny požadované indexy a omezení atd. V nové tabulce.
Doporučení k vyhnout se použití SELECT…INTO
pro produkční kód je zahrnuto jako pravidlo analýzy kódu v SQL Prompt (PE003).
Vytváření tabulek pomocí příkazu SELECT INTO
Funkce SELECT…INTO
na serveru SQL Server byla navržena k uložení nebo ‚přetrvávání‘ zdroje tabulky jako součásti procesu. Zde je jednoduchý příklad:
Zdrojem tabulky však může být mnoho jiných věcí než konvenční tabulka, například uživatelem definovaná funkce, OpenQuery
, OpenDataSource
, klauzule OPENXML
, odvozená tabulka, spojená tabulka, otočná tabulka, vzdálený zdroj dat, proměnná tabulky nebo proměnná funkce. Právě u těchto exotičtějších zdrojů tabulky se syntaxe SELECT…INTO
stává užitečnější.
Je VYBRAT DO SOUČÁSTI ANSI standard?
Normy ANSI podporují konstrukci SELECT…INTO
; nazývá se to singleton select a načte jeden řádek s hodnotami, ale používá se to velmi zřídka (díky Joe Celko za to, že na to upozornil).
Lidé často používají SELECT…INTO
s nedorozuměním, že jde o rychlý způsob kopírování tabulek, a proto je překvapením, že žádný z indexů, omezení, vypočítaných sloupců nebo spouštěčů definovaných v zdrojová tabulka se přenese do nové tabulky. Nelze je zadat ani v prohlášení SELECT…INTO
. Rovněž nedělá nic s možnou hodnotou Null nebo se zachováním vypočítaných sloupců. Všechny tyto úkoly musí být provedeny zpětně se zavedenými daty, což nevyhnutelně vyžaduje čas.
Můžete však použít funkci IDENTITY
(datový typ, seed, increment) k nastavení pole identity a je možné, když je zdrojem jediná tabulka, vytvořit sloupec cílové tabulky do sloupce identity. Právě tato skutečnost pravděpodobně vede vývojáře k domněnce, že přenese další atributy sloupců.
Dále také nemůže vytvářet dělené tabulky, řídké sloupce ani žádný jiný atribut zděděný ze zdrojové tabulky. Jak by to mohlo být, když data možná pocházejí z dotazu zahrnujícího mnoho spojení nebo z nějakého exotického externího zdroje dat?
Od verze SQL 2012 SP1 CU10 může SELECT…INTO
být prováděny paralelně, Od SQL Server 2016 je však paralelní vložení povoleno v konvenčním INSERT INTO…SELECT
příkazu s určitými omezeními, takže jakákoli výhoda výkonu použití SELECT
… INTO
je nyní poněkud snížen. Proces INSERT
INTO
lze také urychlit, pokud jej lze hromadně protokolovat, nikoli plně obnovit, nastavením modelu obnovy k jednoduchému nebo hromadnému přihlášení, vložení do prázdné tabulky nebo haldy a nastavení TABLOCK
nápovědy k tabulce.
Následující text shrnuje některá omezení a omezení při použití SELECT…INTO
.
- Je přenesena vlastnost
IDENTITY
, ale ne pokud:- Příkaz
SELECT
obsahuje spojené tabulky (pomocíJOIN
neboUNION
),GROUP
BY
klauzule nebo agregační funkce.Pokud potřebujete zabránit přenesení vlastnostiIDENTITY
do nové tabulky, ale potřebujete hodnoty sloupce, stojí za to přidatJOIN
do vašeho zdroje tabulky za podmínek, které nikdy nejsou pravdivé, neboUNION
, který neposkytuje žádné řádky. -
IDENTITY
sloupec je uveden více než jednou vSELECT
seznamu - Sloupec
IDENTITY
je součástí výrazu - Sloupec
IDENTITY
pochází ze vzdáleného zdroje dat
- Příkaz
- Nelze
SELECT…INTO
buď parametr s hodnotou tabulky, nebo proměnná tabulky jako cíl, můžete je všakFROM
vybrat. - I když váš zdroj je rozdělená tabulka, nová tabulka je vytvořena ve výchozí skupině souborů. V SQL Server 2017 je však možné určit skupinu souborů, ve které je vytvořena cílová tabulka, pomocí klauzule
ON
. - Můžete zadat
ORDER
BY
, ale je obecně ignorována. Z tohoto důvodu není zaručeno pořadíIDENTITY_INSERT
. - Když je do
SELECT
seznam, odpovídající sloupec v nové tabulce není vypočítaný sloupec. Hodnoty v novém sloupci jsou hodnoty, které byly vypočítány v době, kdy bylSELECT…INTO
spuštěn. - Stejně jako u
CREATE
TABLE
, pokud je příkazSELECT…INTO
obsažen v explicitní transakci, jsou příslušné řádky v ovlivněných systémových tabulkách výlučně uzamčeno, dokud není transakce výslovně potvrzena. Mezitím to povede k blokování dalších procesů, které používají tyto systémové tabulky.
Existují určité nejasnosti ohledně problémů, které mohou nastat při použití SELECT…INTO
pomocí dočasných tabulek. SELECT…INTO
si pro to získal poněkud nespravedlivou pověst, ale bylo to součástí obecnějšího problému zahrnujícího sporu o západku v tempdb
pod velkým zatížením vytváření a mazání malých dočasných tabulek. Když byl SELECT…INTO
přijat s nadšením, mohl by tento typ aktivity výrazně zvýšit. Problém lze snadno vyřešit v systému SQL Server 2000 a dále zavedením použití příznaku trasování TF1118, který již není vyžadován od serveru SQL Server 2016. Úplné vysvětlení najdete v části Nesrovnalosti týkající se TF 1118.
Shrnutí
Stručně řečeno, SELECT…INTO
je dobrý způsob, jak vytvořit tabulku zdroj dočasně perzistentní jako součást procesu, pokud vás nezajímají omezení, indexy nebo speciální sloupce. Není to dobrý způsob kopírování tabulky, protože lze kopírovat pouze nejnutnější základy schématu tabulky. V průběhu let se objevily faktory, které zvýšily nebo snížily přitažlivost SELECT…INTO
, ale obecně je dobré se jí vyhnout, kdykoli je to možné. Místo toho vytvořte tabulku explicitně s celou řadou funkcí, které tabulka obsahuje a které jsou navrženy tak, aby zajistily konzistentnost dat.