Je travaille sur une datawarehouse. Une de nos tables de rassemblement rafraîchies Chaque nuit compte environ 10 millions de rangées. Nous utilisons un outil d'ETL Construit sur mesure que je ne peux pas faire trop de changements. L'outil charge cette table de stadification comme celle-ci:
truncate stage_table;
insert into stage_table with (tablockx) (column1, column2, etc...)
exec load_stage_table @batch_id = @batch_input
Le contenu de load_stage_table
a une certaine configuration et une instruction SELECT. Je ne peux pas partager le code exact, mais voici un exemple de base.
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
Le problème est que lorsque j'exécute la procédure stockée car elle est destinée à être exécutée avec notre outil ETL, le temps d'exécution est de près de 30 minutes. Toutefois, si je modifie la procédure stockée pour avoir l'instruction insertion à l'intérieur, il ne faut que 1 minute.
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
Après avoir exécuté cela à quelques reprises et examiner les plans d'exécution, il semble que le parallélisme n'est pas utilisé lorsque l'insert est en dehors de la procédure stockée.
Charge la table du retour, en dehors de la procédure stockée, empêche le parallélisme? Ou est-ce un indicateur que l'instruction SELECT nécessite un réglage de requête?
INSERT...EXEC
pourrait interdire le parallélisme, mais je doute fort que ce soit le problème principal ici. Le problème est que INSERT...EXEC
Fonctionne différemment de INSERT...SELECT
. Lors de l'insertion des résultats d'une requête (c'est-à-dire une instruction SELECT
ou OUTPUT
clause) dans une table, les résultats sont diffusés dans la table. Si vous regardez le row_count
Et used_page_count
À partir de sys.dm_db_partition_stats
, Vous les émerveillerez immédiatement comme le INSERT...SELECT
Commence.
Mais, lors de l'insertion des résultats d'un EXEC
(typiquement une procédure stockée, mais pourrait être dynamique SQL), la procédure sous-processus/stockée doit être complète avant tout ce qui est inséré dans la table (oui, je viens de tester ce). Si vous regardez le row_count
Et used_page_count
À partir de sys.dm_db_partition_stats
, Vous les semblerez rester au 0
(Ou quoi que ce soit de démarrage) pour A LOOOOONG Temps après que le INSERT...EXEC
commence. Ce n'est pas une recette de réussite lorsque la procédure stockée renvoie des millions de lignes car les résultats doivent être stockés quelque part avant d'être insérés dans la table.