SELECT…INTOステートメント(PE003)を使用する場合
SQLServerでSELECT…INTO
を使用して、テーブルソースから新しいテーブルを作成できます。 SQL Serverは、SELECT
リストの式の属性を使用して新しいテーブルの構造を定義します。
SQL Server 2005より前は、
は、データベースのシステムテーブルのスキーマロックを取得し、クエリの実行中にSQL Serverが応答しなくなったため、パフォーマンスの「コード臭」でした。これは、暗黙的なトランザクションのDDLステートメントであり、データが同じSQLステートメント内に挿入されるため、必然的に長時間実行されるためです。ただし、この動作はSQL Server 2005で修正され、ロックモデルが変更されました。
SELECT…INTO
は、INSERT
INTO…SELECT…
。これは主に、SELECT…INTO
操作が可能な場合は一括ログに記録されていたことが原因でした。 INSERT
INTO
を一括ログに記録できるようになりましたが、
はこれらのバージョンで並列化できますが、INSERT
INTO
の並列化のサポートはSQLServerでのみ登場しました2016年。ただし、SELECT…INTO
を使用すると、新しいテーブルで必要なすべてのインデックスや制約などを定義するタスクが引き続きあります。
推奨事項SELECT…INTO
の使用を避けてください。本番コードは、SQLプロンプト(PE003)のコード分析ルールとして含まれています。
SELECTINTOステートメントを使用したテーブルの作成
SQLServerのSELECT…INTO
機能は、プロセスの一部としてテーブルソースを格納または「永続化」するように設計されています。簡単な例を次に示します。
ただし、テーブルソースは、ユーザー定義関数、OpenQuery
など、従来のテーブル以外の多くのものにすることができます。 OpenDataSource
、OPENXML
句、派生テーブル、結合テーブル、ピボットテーブル、リモートデータソース、テーブル変数、または可変関数。 SELECT…INTO
構文がより便利になるのはこれらのよりエキゾチックなテーブルソースです。
SELECTINTOはANSIの一部です標準?
ANSI標準はSELECT…INTO
構造をサポートしています。これはシングルトン選択と呼ばれ、値を含む単一の行をロードしますが、ほとんど使用されません(これを指摘してくれたJoe Celkoに感謝します)。
SELECT…INTO
は、テーブルをすばやくコピーする方法であると誤解されて使用されることがよくあります。そのため、で定義されているインデックス、制約、計算列、トリガーがないのは驚きです。ソーステーブルが新しいテーブルに転送されます。 SELECT…INTO
ステートメントでも指定できません。また、null可能性や計算列の保持についても何もしません。これらのタスクはすべて、データを配置した状態で遡及的に実行する必要があり、必然的に時間がかかります。
ただし、関数IDENTITY
(datatype、seed、インクリメント)IDフィールドを設定し、ソースが単一のテーブルの場合、宛先テーブルの列をID列にすることができます。開発者が他の列属性を転送すると想定するのはこの事実です。
さらに、パーティションテーブル、スパース列、またはソーステーブルから継承された他の属性を作成することもできません。データが多くの結合を含むクエリから、またはエキゾチックな外部データソースから取得されている可能性がある場合、どうすればよいでしょうか?
SQL 2012 SP1 CU10以降、SELECT…INTO
ただし、SQL Server 2016以降、並列挿入は従来のINSERT INTO…SELECT
ステートメントで許可されていますが、特定の制限があるため、…INTO
はかなり減少しています。 INSERT
INTO
プロセスは、完全に回復するのではなく、一括ログに記録できる場合は、回復モデルを設定することで高速化することもできます。単純または一括ログに記録し、空のテーブルまたはヒープに挿入し、テーブルのTABLOCK
ヒントを設定します。
以下に、いくつかの制限とSELECT…INTO
を使用する場合の制限。
- 列の
IDENTITY
プロパティは転送されますが、次の場合は転送されません。-
SELECT
ステートメントには、結合されたテーブルが含まれています(JOIN
またはUNION
)、GROUP
BY
句、または集計関数。IDENTITY
プロパティが新しいテーブルに引き継がれないようにする必要があるが、列の値が必要な場合は、JOIN
は、決して真ではない条件でテーブルソースに送信するか、行を提供しないUNION
に送信します。 -
IDENTITY
列がSELECT
リストに複数回リストされている -
IDENTITY
列は一部です式の例 -
IDENTITY
列はリモートデータソースからのものです
-
-
宛先としてテーブル値パラメーターまたはテーブル変数のいずれかを選択できますが、FROM
を選択できます。
ON
句を使用して、宛先テーブルが作成されるファイルグループを指定できます。 BY
句ですが、通常は無視されます。このため、IDENTITY_INSERT
の順序は保証されません。
SELECT
リストの場合、新しいテーブルの対応する列は計算列ではありません。新しい列の値は、SELECT…INTO
が実行されたときに計算された値です。CREATE
TABLE
ステートメント、SELECT…INTO
ステートメントが明示的なトランザクション内に含まれている場合、影響を受けるシステムテーブルの基になる行はトランザクションが明示的にコミットされるまで排他的にロックされます。当面の間、これにより、これらのシステムテーブルを使用する他のプロセスでブロックが発生します。 SELECT…INTO
一時テーブルを使用します。 SELECT…INTO
はこれについてやや不公平な評判を得ていますが、これは高負荷の下でのtempdb
でのラッチ競合を含むより一般的な問題の一部でした小さな一時テーブルの作成と削除の。 SELECT…INTO
が熱狂的に採用されたとき、この種の活動を大幅に増やすことができました。この問題は、SQL Server 2016以降では不要になったトレースフラグTF1118の使用を導入することで、SQL Server2000以降で簡単に修正できます。完全な説明については、TF1118に関する誤解を参照してください。
要約
要約すると、SELECT…INTO
はテーブルを作成するための良い方法です-制約、インデックス、または特別な列を気にしない場合は、プロセスの一部として一時的に永続的なソース。テーブルスキーマの最も重要な要素のみをコピーできるため、テーブルをコピーするのは良い方法ではありません。何年にもわたって、SELECT…INTO
の魅力を増減させる要因がありましたが、全体として、可能な限り使用しないことをお勧めします。代わりに、データの一貫性を確保するように設計された、テーブルが持つすべての機能を使用して、テーブルを明示的に作成してください。