Un auto simple, rejoindre sembleraient bien meilleurs résultats qu'une ligne sous-requête faisant référence
Generate 10k lignes de données de test:
drop table test10k
create table test10k (Id int, Number int, constraint test10k_cpk primary key clustered (id))
;WITH digits AS (
SELECT 0 as Number
UNION SELECT 1
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9
)
,numbers as (
SELECT
(thousands.Number * 1000)
+ (hundreds.Number * 100)
+ (tens.Number * 10)
+ ones.Number AS Number
FROM digits AS ones
CROSS JOIN digits AS tens
CROSS JOIN digits AS hundreds
CROSS JOIN digits AS thousands
)
insert test10k (Id, Number)
select Number, Number
from numbers
Je tirerais le cas particulier des 3 premières lignes de la requête principale, vous pouvez UNION tous ceux de retour si vous le voulez vraiment dans le jeu de lignes. Auto de jointure:
;WITH NumberedRows
AS
(
SELECT rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
FROM test10k rta
)
SELECT nr.ID, nr.Number,
avg(trailing.Number) as MovingAverage
FROM NumberedRows nr
join NumberedRows as trailing on trailing.RowNumber between nr.RowNumber-3 and nr.RowNumber-1
where nr.Number > 3
group by nr.id, nr.Number
Sur ma machine, cela prend environ 10 secondes, l'approche sous-requête Aaron Alton démontré prend environ 45 secondes (après avoir changé pour refléter ma table de source de test):
;WITH NumberedRows
AS
(
SELECT rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
FROM test10k rta
)
SELECT nr.ID, nr.Number,
CASE
WHEN nr.RowNumber <=3 THEN NULL
ELSE ( SELECT avg(Number)
FROM NumberedRows
WHERE RowNumber < nr.RowNumber
AND RowNumber >= nr.RowNumber - 3
)
END AS MovingAverage
FROM NumberedRows nr
Si vous faites un SET STATISTICS PROFILE ON, vous pouvez voir que la jointure automatique a 10k s'exécute sur le spool de la table. La sous-requête a 10k s'exécute sur le filtre, l'agrégat et d'autres étapes.
Quel type de base de données SQL que vous utilisez? –
J'utilise SQL Server 2008. – HYP
Im pensant que c'est l'un de ces très rares cas où les curseurs vont être le plus rapide ... juste garder les 3 dernières lignes vars ... –