web-dev-qa-db-fra.com

Comparaison des performances entre l'utilisation de la fonction Join et Window pour obtenir les valeurs d'avance et de retard

J'ai une table avec 20 millions de lignes et chaque ligne a 3 colonnes: time, id et value. Pour chaque id et time, il y a value pour le statut. Je veux connaître les valeurs de plomb et de décalage d'un certain time pour un id spécifique.

J'ai utilisé deux méthodes pour y parvenir. Une méthode utilise la jointure et une autre méthode utilise les fonctions de fenêtre lead/lag avec un index cluster sur time et id.

J'ai comparé les performances de ces deux méthodes par le temps d'exécution. La méthode de jointure prend 16,3 secondes et la méthode de fonction de fenêtre prend 20 secondes, sans compter le temps de création de l'index. Cela m'a surpris car la fonction window semble être avancée alors que les méthodes de jointure sont en force brute.

Voici le code des deux méthodes:

Créer un index

create clustered index id_time
 on tab1 (id,time)

Méthode Join

select a1.id,a1.time
   a1.value as value, 
   b1.value as value_lag,
   c1.value as value_lead
into tab2
from tab1 a1
left join tab1 b1
on a1.id = b1.id
and a1.time-1= b1.time
left join tab1 c1
on a1.id = c1.id
and a1.time+1 = c1.time

Statistiques d'E/S générées à l'aide de SET STATISTICS TIME, IO ON:

Statistics for Join Method

Voici le plan d'exécution pour la méthode join

Méthode de fonction de fenêtre

select id, time, value, 
   lag(value,1) over(partition by id order by id,time) as value_lag,
   lead(value,1) over(partition by id order by id,time) as value_lead
into tab2
from tab1

(La commande uniquement par time permet d'économiser 0,5 seconde.)

Voici le plan d'exécution pour méthode de la fonction fenêtre

Statistiques IO

[Statistics for Window function method 4]


J'ai vérifié les données dans sample_orig_month_1999 et il semble que les données brutes soient bien ordonnées par id et time. Est-ce la raison de la différence de performances?

Il semble que la méthode de jointure ait plus de lectures logiques que la méthode de fonction de fenêtre, alors que le temps d'exécution pour la première est en fait inférieur. Est-ce parce que le premier a un meilleur parallélisme?

J'aime la méthode de la fonction fenêtre en raison du code concis, existe-t-il un moyen de l'accélérer pour ce problème spécifique?

J'utilise SQL Server 2016 sur Windows 10 64 bits.

10
Jason

Les performances en mode ligne relativement faibles des fonctions de fenêtre LEAD et LAG par rapport aux jointures automatiques ne sont pas nouvelles. Par exemple, Michael Zilberstein a écrit à ce sujet sur SQLblog.com en 2012. Il y a pas mal de frais généraux dans les opérateurs de plan Segment, Sequence Project, Window Spool et Stream Aggregate (répétés):

Plan section

Dans SQL Server 2016, vous disposez d'une nouvelle option, qui consiste à activer le traitement en mode batch pour les agrégats de fenêtres. Cela nécessite une sorte d'index columnstore sur la table, même s'il est vide. La présence d'un index columnstore est actuellement requise pour que l'optimiseur considère les plans en mode batch. En particulier, il permet à l'opérateur en mode batch Window Aggregate beaucoup plus efficace.

Pour tester cela dans votre cas, créez un index columnstore non cluster vide:

 -- Empty CS index
CREATE NONCLUSTERED COLUMNSTORE INDEX dummy 
ON dbo.tab1 (id, [time], [value]) 
WHERE id < 0 AND id > 0;

La requête:

SELECT
    T1.id,
    T1.[time],
    T1.[value],
    value_lag = 
        LAG(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time]),
    value_lead =
        LEAD(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time])
FROM dbo.tab1 AS T1;

Devrait maintenant donner un plan d'exécution comme:

Batch mode row store plan

... qui pourrait bien s'exécuter beaucoup plus rapidement.

Vous devrez peut-être utiliser une OPTION (MAXDOP 1) ou un autre indice pour obtenir la même forme de plan lors du stockage des résultats dans un nouveau tableau. La version parallèle du plan nécessite un tri en mode batch (ou éventuellement deux), qui peut être un peu plus lent. Cela dépend plutôt de votre matériel.

Pour plus d'informations sur l'opérateur d'agrégation de fenêtres en mode batch, consultez les articles suivants d'Itzik Ben-Gan:

11
Paul White 9