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)、GROUPBY句、または集計関数。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の魅力を増減させる要因がありましたが、全体として、可能な限り使用しないことをお勧めします。代わりに、データの一貫性を確保するように設計された、テーブルが持つすべての機能を使用して、テーブルを明示的に作成してください。