web-dev-qa-db-ja.com

テーブルに挿入Exec SPパフォーマンスが悪い

私はデータウェアハウスに取り組んでいます。毎晩更新されるステージングテーブルの1つには、約1000万行があります。あまり変更を加えられないカスタムビルドのETLツールを使用しています。ツールは、このステージングテーブルを次のようにロードします。

truncate stage_table;
insert into stage_table with (tablockx) (column1, column2, etc...)
exec load_stage_table @batch_id = @batch_input

load_stage_tableの内容には、いくつかの設定とselectステートメントがあります。正確なコードを共有することはできませんが、基本的な例を次に示します。

create table load_stage_table
(
     @batch_id varchar(max) = null
)
as 

-- <update batch_id in batch_table>

-- collect data

select
    column1 = table1.column1,
    column2 = table2.column2,
    ...
from table1
join table2
    on table2.id = table1.table2_id
-- many more similar joins

問題は、ETLツールで実行することを目的としてストアドプロシージャを実行すると、実行時間がほぼ30分になることです。ただし、ストアドプロシージャを変更して内部にinsertステートメントを含めると、1分しかかかりません。

    create table load_stage_table
(
     @batch_id varchar(max) = null
)
as 

-- <update batch_id in batch_table>

-- collect data
insert into stage_table with (tablockx) (column1, column2, etc...)
select
    column1 = table1.column1,
    column2 = table2.column2,
    ...
from table1
join table2
    on table2.id = table1.table2_id
-- many more similar joins

これを数回両方の方法で実行し、実行プランを調べた後、挿入がストアドプロシージャの外部にある場合、並列処理は使用されないようです。

ストアドプロシージャの外で、リターンからテーブルをロードすると、並列処理が妨げられますか?または、これは、selectステートメントにクエリのチューニングが必要であることを示していますか?

5
Ryati

INSERT...EXECmight並列処理を禁止しますが、それがここでの主な問題であることは間違いありません。問題は、INSERT...EXECINSERT...SELECTとは異なる動作をすることです。クエリの結果(つまりSELECTステートメントまたはOUTPUT句)をテーブルに挿入すると、結果はテーブルにストリーミングされます。 row_countused_page_countsys.dm_db_partition_statsを視聴している場合、INSERT...SELECTが始まるとすぐに増加するように見えます。

しかし、EXEC(通常はストアドプロシージャですが、動的SQLの可能性があります)の結果を挿入する場合、サブプロセス/ストアドプロシージャは、テーブルに何かが挿入される前に完全に完了する必要があります(はい、テストしました)この)。 row_countused_page_countsys.dm_db_partition_statsを視聴している場合、それらは0(または最初に開始したもの)にlooooongで留まっているように見えます。 = INSERT...EXECが開始してからの時間。ストアドプロシージャが数百万行を返す場合、これらの結果はテーブルに挿入される前にどこかに保存する必要があるため、これは成功のレシピではありません。

8
Solomon Rutzky