Comment accélérer la requête de mise à jour dans SQL Server 2008?

update orders set tname = (select top 1 t.task from task t where prod_typ='2' and sorder_nbr = t.ORDER_NBR order by t.strt_dt desc) where Prod_type='2' update orders set tname= (select top 1 t.task from task t where prod_typ='1' and sorder_nbr=t.ORDER_NBR order by t.strt_dt desc) where Prod_type='1' 

J'essaie de mettre à jour la colonne tname de la table orders par la dernière tâche de la table des task

Et la condition est prod_typ de la table des orders est 1 et sorder_nbr de la table des orders et order_nbr de la table des task sont égales

Ma première instruction de mise à jour fonctionne bien là où les lignes sont 900k et pour les lignes de deuxième mise à jour sont 400k pour la deuxième instruction de mise à jour cela prend plus d'une heure et enfin j'ai annulé la requête

1) Vous interrogez et ma requête:

 update orders set tname = (select top 1 t.task from task t where prod_type='2' and order_nbr = t.ORDER_NBR order by t.strt_dt desc) where Prod_type='2'; go update o set tname = (select top 1 t.task from task t where prod_type='2' and o.order_nbr = t.ORDER_NBR order by t.strt_dt desc) from dbo.orders o where Prod_type='2'; go 

Les plans d'exécution réels: entrez la description de l'image ici

Comme vous pouvez le voir, si le classment par défaut pour le DB actuel est CI (insensible à la casse), le prédicat order_nbr=t.ORDER_NBR force SQL Server à comparer les valeurs de t.ORDER_NBR avec les valeurs order_nbr de la même table task t . Regardez le premier plan d'exécution qui correspond à la première requête.

Pour résoudre juste ce problème, j'ai utilisé un autre alias dbo.orders o et j'ai réécrit le prédicat ainsi o.order_nbr = t.ORDER_NBR . Vous pouvez voir cela aussi dans le deuxième plan d'exécution.

En fonction du nombre de tâches pour chaque order_num & prod_type, vous pouvez tester S # 1 s'il y a beaucoup de tâches ou S # 2 s'il y a une petite quantité de tâches par order_num & prod_type. Encore une fois, vous devez tester avec vos données pour voir quelle solution est la meilleure.

2) Solution n ° 1:

 UPDATE o SET tname = COALESCE( (SELECT TOP(1) t.task FROM dbo.task t WHERE t.prod_type=o.Prod_type AND o.order_nbr = t.ORDER_NBR ORDER BY t.strt_dt DESC), tname ) FROM dbo.orders o WHERE o.Prod_type IN ('1', '2'); 

3) Solution n ° 2:

 UPDATE o SET tname = lt.task FROM dbo.orders o INNER JOIN ( SELECT src.order_nbr, src.prod_type, src.task FROM ( SELECT t.ORDER_NBR, t.prod_type, t.task, ROW_NUMBER() OVER(PARTITION BY t.ORDER_NBR, t.prod_type ORDER BY t.strt_dt DESC) RowNum FROM dbo.task t ) src WHERE src.RowNum = 1 ) lt -- last task ON o.order_nbr = lt.ORDER_NBR AND o.prod_type = lt.prod_type WHERE o.Prod_type IN ('1', '2'); 

Si vous avez des questions, n'hésitez pas à requestr.

4) Un index sur dbo.task(order_nbr, prod_type, strt_dt) include (task) devrait aider les deux solutions.

5) Vous devriez également publier les plans d'exécution réels.

Si la taille des données est plus grande que je vous suggère d'utiliser des variables pour mettre à jour le tableau, ou Utiliser CTE pour mettre à jour

Mettre à jour une table en utilisant CTE et NEWID ()

Mise à jour de l'logging en utilisant CTE?

J'espère que cela aidera

avec tname (t.task) as (select le top 1 t.task de la tâche t où prod_typ = '2' et order_nbr = t.ORDER_NBR commandz par t.strt_dt desc) insérez dans les commands (t.task)

Essayez quelque chose comme ça. Cela mettra à jour prod_type de 1 et 2 en même time.

 UPDATE orders SET tname = t1.task FROM orders o CROSS APPLY ( SELECT order_nbr, prod_type, t.task, row_number() OVER (PARTITION BY order_nbr, prod_type ORDER BY strt_dt DESC) rownumber FROM task t WHERE o.prod_type = t.prod_type AND o.order_nbr = t.order_nbr) t1 WHERE t1.rownumber = 1 AND o.prod_type in (1,2) 

L'utilisation d'une requête CTE accélérera cela, car la sous-requête n'a pas besoin d'être créée pour chaque ligne, elle est pré-préparée. Voici le sqlfiddle

  ;with cteTaskNames as ( select top 1 t.task from task t where prod_type='2' and order_nbr=t.ORDER_NBR order by t.strt_dt desc ) update orders set tname = (select task from cteTaskNames) where Prod_type='2' go 

De plus, 1) "prod_type" est-il un champ entier ou un champ de type string? 2) Si vous ajoutez un groupe par dans le cte, vous pouvez faire une jointure interne sur les commands et cte requête pour exécuter toutes les mises à jour à la fois au lieu de faire chaque requête.