私はデータウェアハウスに取り組んでいます。毎晩更新されるステージングテーブルの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ステートメントにクエリのチューニングが必要であることを示していますか?
INSERT...EXEC
might並列処理を禁止しますが、それがここでの主な問題であることは間違いありません。問題は、INSERT...EXEC
がINSERT...SELECT
とは異なる動作をすることです。クエリの結果(つまりSELECT
ステートメントまたはOUTPUT
句)をテーブルに挿入すると、結果はテーブルにストリーミングされます。 row_count
のused_page_count
とsys.dm_db_partition_stats
を視聴している場合、INSERT...SELECT
が始まるとすぐに増加するように見えます。
しかし、EXEC
(通常はストアドプロシージャですが、動的SQLの可能性があります)の結果を挿入する場合、サブプロセス/ストアドプロシージャは、テーブルに何かが挿入される前に完全に完了する必要があります(はい、テストしました)この)。 row_count
のused_page_count
とsys.dm_db_partition_stats
を視聴している場合、それらは0
(または最初に開始したもの)にlooooongで留まっているように見えます。 = INSERT...EXEC
が開始してからの時間。ストアドプロシージャが数百万行を返す場合、これらの結果はテーブルに挿入される前にどこかに保存する必要があるため、これは成功のレシピではありません。