J'ai un curseur qui fonctionne longtemps pendant environ minutes que j'ai pu réduire pour courir en quelques secondes en utilisant un CTE (expressions de table communes). L'ensemble de résultats a été identique jusqu'à ce qu'il y ait eu une condition où je dois obtenir les 10 meilleures valeurs pour chaque itération du curseur que je ne suis pas capable de faire la logique basée sur la logique.
En supposant que la logique basée sur le curseur soit:
SET @mycurse = CURSOR FOR
SELECT value FROM sometable
OPEN @mycurse
FETCH NEXT FROM @mycurse INTO @SomeVariable
IF @@FETCH_STATUS <> 0
Print 'Error in the Cursor Fetch Statement'
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO @TOP10
SELECT Value1,Value2,Value3,Value4
FROM (
select Value1,Value1,Value3,Value4 from BaseTable where SomeVariable=@SomeVariable
)
FETCH NEXT FROM @mycurse INTO @SomeVariable
END
CLOSE @mycurse
Et la mise en scène basée sur la CTE ressemble à ceci:
;With myCTE(value)
as
(
SELECT value FROM sometable
)
INSERT INTO @TOP10
SELECT Value1,Value2,Value3,Value4
FROM
(select
Value1, Value1, Value3, Value4
from BaseTable BT, myCTE MC
where BT.SomeVariable = MC.SomeVariable)
Au fur et à mesure que vous voyez à la fois de fonctionner et de retourner un résultat identique, avec la version CTE en utilisant considérablement moins de temps. Mais la logique d'avoir les 10 meilleures valeurs le rend faux, il ne renvoie que 10 valeurs où il est censé renvoyer 20 valeurs.
SET @mycurse = CURSOR FOR
SELECT value FROM sometable
OPEN @mycurse
FETCH NEXT FROM @mycurse INTO @SomeVariable
IF @@FETCH_STATUS <> 0
Print 'Error in the Cursor Fetch Statement'
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO @TOP10
SELECT top 10 Value1,Value2,Value3,Value4
FROM
(select
Value1, Value1, Value3, Value4
from BaseTable
where SomeVariable = @SomeVariable)
FETCH NEXT FROM @CUR_Liability INTO @VarLiability
END
CLOSE @CUR_Liability
Alors s'il vous plaît me fournir une solution à ce scénario, il n'a pas nécessairement besoin d'être basé sur la CTE, mon objectif est de réduire le temps d'exécution. De plus, je peux mettre à jour le jeu de résultats de l'échantillon si cela n'est pas assez clair. Merci d'avance.
Mise à jour: J'ai réussi à utiliser une solution à l'aide de Row_Number()
Fonction mais je suis toujours curieux d'autres options.
Si je comprends bien, et que vous souhaitez insérer 10 valeurs de la 2e table pour chaque itération du curseur (ou de la CTE), vous pouvez utiliser ceci:
; WITH myCTE (value) AS
( SELECT value FROM sometable )
INSERT INTO @TOP10
SELECT t.Value1, t.Value2, t.Value3, t.Value4
FROM myCTE AS mc
CROSS APPLY
( SELECT TOP (10)
bt.Value1, bt.Value2, bt.Value3, bt.Value4
FROM BaseTable AS bt
WHERE bt.SomeVariable = mc.value
ORDER BY <SomeColumns> -- needs something here
) AS t ;
Vous avez également besoin d'un ORDER BY
Dans la sous-requête avec TOP
pour être cohérent. Sans order by
, Le moteur de base de données est libre de renvoyer des 10 lignes correspondant aux conditions.
Il pourrait également être fait en utilisant ROW_NUMBER()
:
; WITH myCTE (Value1, Value2, Value3, Value4) AS
( SELECT bt.Value1, bt.Value2, bt.Value3, bt.Value4,
Rn = ROW_NUMBER() OVER (PARTITION BY bt.SomeVariable
ORDER BY <SomeColumns>)
FROM sometable AS s
JOIN BaseTable AS bt
ON bt.SomeVariable = s.value
)
INSERT INTO @TOP10
SELECT Value1, Value2, Value3, Value4
FROM myCTE
WHERE Rn <= 10 ;