同僚や研究からさまざまなことを聞いています。一時テーブルを作成するときのパフォーマンスの優れたガイドラインは何ですか?小さなテーブルの場合、違いはごくわずかです。
例:テーブルには20列、5,000万行あります。
私はDBAの状態を示しましたが、コンパイラー/パーサーはその場で列のデータ型を見つける必要がないため、挿入先が高速です。 Select intoを示す他の人はより速いです。パフォーマンステストを実施しましたが、select intoの方が少し速いようです。
どちらがより速く、なぜであるかを理解するための良い原則は何ですか? Microsoftは、注意深くプログラミングするために、への挿入を同じくらい高速に行うように最適化すると思います。
記事は次のように述べています。
SQL ServerのSELECT INTOと一時テーブルのINSERT INTOのパフォーマンス
INSERT ... INTOコマンドは、挿入/更新/削除操作のためにキャッシュに作成されたデータページを再利用します。また、テーブルがドロップされると、テーブルが切り捨てられます。 SELECT ... INTOコマンドは、通常のテーブルと同様のテーブル作成用の新しいページを作成し、一時テーブルが削除されると物理的にそれらを削除します。
問題は、Microsoftがselect intoと同じ速度でinsert intoを実行するように最適化しないのはなぜですか?
データウェアハウス用に作成するストアドプロシージャは500以上あり、一時的な使用には適切なガイドラインが必要です。
この記事では、実際にはパフォーマンスと理由に焦点を当てていません。
記事の人は良い点を述べました:
これは主に、SQL Serverが宛先テーブルの競合がないことを認識しているためです。 #temp with(tablock)select * from ..への挿入のパフォーマンスは、select * into #temp fromのパフォーマンスとほぼ同じです。
あなたは2つの異なることを論じている2つの異なる記事を引用しました。
最初の記事は_insert..select
_を_select into
_と一時テーブルについて比較し、2番目の記事はこれら2つを比較します =)一般的に。
一般に、_insert..select
_は完全にログに記録される操作であるため、低速です。 _select into
_は、simple
および_bulk logged
_復旧モデルに最小限記録されます。
あなたが引用した最後のコメントはinsert into with(tablock)
に関するものです。このwith(tablock)
は、いくつかの追加条件の下で_insert into
_を最小限に記録できます。これはヒープであり、インデックスを持たないはずです。
完全なガイドはここにあります: データ読み込みパフォーマンスガイド
次の表にまとめます。
SQL Server 2016以降の更新に注意してください SQL Server 2016、最小限のログ記録と一括読み込み操作でのBatchsizeの影響 Parik Savjani(Microsoft SQL Server Tigerチームのシニアプログラムマネージャー)。更新されたテーブルは次のとおりです。
最初の記事について。 一時テーブルの特定のケースについて説明します。
tempdb
データベースは、単純な復旧モデルに常に含まれ、tempdb
へのログインが異なるため、特別です。サーバーを再起動するたびにtempdb
が再作成されます。これは、tempdb
のクラッシュリカバリが行われないことを意味します。これは、tempdb
へのログインに変更後のイメージが不要であることを意味しますデータ、必要に応じてロールバックを実行できる「前」のイメージのみ。これは、tempdb
ヒントがなくても_insert into..select
_も最小限にtablock
にログインするという事実につながります(最初の記事で説明したheap
の場合) 。
結論「ロギングアスペクトの下での_select into
_対_insert..select
_」:
heap
の場合、_insert into..select
_は一時テーブルの場合の_select into
_と同様に機能し、tablock
ヒントを使用しない場合は一般に遅くなります。
2番目の側面は、並列実行の可能性です。
_Select into
_はSQL Server 2014以降で並列実行でき、並列_insert...select
_はSQL Server 2016で初めて実装されました。
SQL Server 2012の一時テーブルの_select into
_と_insert into ..select
_のパフォーマンスの違いは再現されませんでした。これらはすべてシリアルで実行されました。
どちらがより速く、なぜであるかを理解するための良い原則は何ですか? Microsoftは、注意深くプログラミングするために、への挿入を同じくらい高速に行うように最適化すると思います。
この質問のようなものを分析するときに私が従おうとする原則は次のとおりです。
私はあなたの質問に対処する2つのドキュメントを知っています。最初のものは ブログ投稿 で、一時テーブルのSELECT INTO
は、SQL Server 2014の時点で、熱心な書き込みに対して異なる動作をすることを示しています。これは仕様によるものです。ですから、小さなテーブルの場合、その差は最小限であると言っても間違いだとは思いません。どちらかと言えば、ブログの投稿で説明されている最適化は、小さなテーブル向けに設計されているようです。
SQL Server 2014の変更は、これらのページをTEMPDBデータファイルにすばやくフラッシュする必要性を緩和することです。 …#tmp…への選択を行うか、TEMPDB内のSORTを使用してインデックスを作成すると、SQL Serverはこれが一時的な操作である可能性があることを認識します。このような操作に関連付けられたページは、非常に短い時間枠で作成、ロード、クエリ、および解放できます。
例:8ミリ秒で実行されるストアドプロシージャを使用できます。そのストアドプロシージャで、選択して…#tmp…を選択し、#tmpを使用して、ストアドプロシージャの完了時にドロップします。
SQL Server 2014より前のバージョンでは、select intoによって、蓄積されたすべてのページがディスクに書き込まれた可能性があります。 SQL Server 2014の熱心な書き込み動作により、これらのページが以前のバージョンほど迅速にディスクに強制されなくなりました。この動作により、ページがRAM(バッファプール)に格納され、クエリが実行され、テーブルが削除(バッファプールから削除され、フリーリストに返されます)されます。可能な場合はTEMPDBのパフォーマンスを回避して物理I/Oを回避することで、一括操作が大幅に増加し、I/Oパスリソースへの影響も軽減されます。
ドキュメントの2番目の部分 は、SQL Server 2016でTABLOCK
ヒントなしでINSERT INTO ... SELECT
を使用して一時テーブルに並列挿入できるが、TABLOCK
ヒントが必要であることを説明していますSP1および将来のバージョンで。
この問題は、SQL Server 2016 Service Pack 1で最初に修正されました。 SQL Server 2016 SP1を適用すると、ローカル一時テーブルへのINSERT..SELECTの並列INSERTがデフォルトで無効になり、PFSページの競合が減少し、同時ワークロードの全体的なパフォーマンスが向上します。ローカル一時テーブルへの並列INSERTが必要な場合、ユーザーはローカル一時テーブルに挿入するときにTABLOCKヒントを使用する必要があります。
元のステートメントに戻ると、2つのうちどちらが高速になるかを論理的に推測することはできません。何が速くなるかは、Microsoftがソフトウェアをどのように設計したか、およびワークロードの特性によって異なります。列の定義を作成するのに必要な時間を推測するだけでは役に立ちません。テストは役に立ちます。テストでSELECT INTO
の方がそれよりも速いことがわかった場合。それだけの価値があるので、私はパフォーマンスに注意を払ってデータウェアハウスの読み込みにも取り組んでおり、2つのアプローチの違いが心配に値するものであるのを見たことはありません。
SQL Serverが扱うすべての値にはデータ型があります。 SELECTの結果はすべて型指定されています。そのため、SELECT..INTOはその場で推定データ型を持っている必要はありません-それらはSELECTによって定義されます。
対照的に、INSERT..SELECTを使用すると、ソース列と宛先列は異なる型になりますが、互換性があります。その後、CPUサイクルを消費する暗黙の型強制が行われます。実行時間の違いを測定できるかどうかはわかりませんでした。