web-dev-qa-db-fra.com

Insérer dans la table Exec SP avec de mauvaises performances

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?

5
Ryati

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.

8
Solomon Rutzky