Un de ces jours, je me suis retrouvé à oprimiser une procédure stockée qui traitait à travers un courseur une table de quelques millions d'enregistrements. Le traitement consistait à faire une mise à jour de chaque dernière enregistrement d'un regroupement de données.
Pour réaliser l'optimisation la première étape était d'obtenir la liste des enregistremens à mettre à jour (Ex : sur AdventureWorks) :
SELECT * FROM
(SELECT Sale.CustomerID, Cust.LastName, Sale.SalesOrderID, Sale.OrderDate,
ROW_NUMBER() OVER (partition by CustomerID order by OrderDate desc)as RowNumber
FROM Sales.SalesOrderHeader Sale
inner join Sales.Customer Cust on Cust.CustomerID=Sale.CustomerID) t2
WHERE RowNumber=1
En passant par ROW_NUMBER avec partitionnement tout devient plus simple.
Et maintenant on peut éliminer le courseur et utiliser une mise à jour en join:
update Sales.SalesOrderHeader
set DueDate=getdate()
from
Sales.SalesOrderHeader s1 inner join
(
SELECT * FROM
(SELECT Sale.CustomerID, Cust.LastName, Sale.SalesOrderID, Sale.OrderDate,
ROW_NUMBER() OVER (partition by CustomerID order by OrderDate desc)as RowNumber
FROM Sales.SalesOrderHeader Sale
inner join Sales.Customer Cust on Cust.CustomerID=Sale.CustomerID) t2
WHERE RowNumber=1
) t1 on t1.SalesOrderID=s1.SalesOrderID
La procédure est valable pour retrouver et mettre à jour le 2-ème,..., n-ème élément.