SQL Server 2008 Optimize FULL JOIN avec les déclarations de isNull
-
26-09-2019 - |
Question
HI Tous
J'espérais que quelqu'un pourrait me aider à améliorer une requête que je dois exécuter périodiquement. À l'heure actuelle, il faut plus de 40 minutes pour exécuter. Il utilise la mémoire complète allouée pendant ce temps, mais l'utilisation du processeur à 2 la plupart du temps serpente% -. 5%, chaque maintenant et puis sauter à 40% pendant quelques secondes
J'ai ce tableau (exemple simplifié):
CREATE TABLE [dbo].[dataTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[dteEffectiveDate] [date] NULL,
[dtePrevious] [date] NULL,
[dteNext] [date] NULL,
[Age] [int] NULL,
[Count] [int] NULL
) ON [PRIMARY]
GO
Voici quelques valeurs d'entrée:
INSERT INTO [YourDB].[dbo].[dataTable]
([dteEffectiveDate]
,[dtePrevious]
,[dteNext]
,[Age]
,[Count])
VALUES
('2009-01-01',NULL,'2010-01-01',40,300),
('2010-01-01','2009-01-01', NULL,40,200),
('2009-01-01',NULL, '2010-01-01',20,100),
('2010-01-01','2009-01-01', NULL,20,50),
('2009-01-01',NULL,'2010-01-01',30,10)
GO
Chaque entrée a un champ dteEffectiveDate. En outre, chacun a un dtePrevious et dteNext, ce qui reflète les dates du précédent / suivant le plus proche date. Maintenant, ce que je veux est une requête qui calcule la valeur médiane sur les champs de comptage entre les périodes successives, dans un certain âge.
Ainsi, par exemple, dans les données ci-dessus, pour 40 ans, nous avons 300 à 200 et 2009/01/01 à 2010/01/01 de sorte que la requête doit produire 250.
Notez que l'âge 30 n'a qu'une seule entrée, 10. Ceci est à 2009/01/01. Il n'y a pas d'entrée à 2010/01/01, mais nous savons que les données ont été capturées à ce point, donc le fait qu'il n'y a rien signifie que 30 est 0 à cette date. D'où la requête doit produire 5.
Pour y parvenir, j'utiliser un FULL JOIN de la table sur elle-même, et d'utiliser ISNULL pour sélectionner des valeurs. Voici mon code:
SELECT
ISNULL(T1.dteEffectiveDate,T2.dtePrevious) as [Start Date]
,ISNULL(T1.dteNext,T2.dteEffectiveDate) as [End Date]
,ISNULL(T1.Age,T2.Age) as Age
,ISNULL(T1.[Count],0) as [Count Start]
,ISNULL(T2.[Count],0) as [Count End]
,(ISNULL(T1.[Count],0)+ISNULL(T2.[Count],0))/2 as [Mid Count]
FROM
[ExpDBClient].[dbo].[dataTable] as T1
FULL JOIN [ExpDBClient].[dbo].[dataTable] as T2
ON
T2.dteEffectiveDate = T1.dteNext
AND T2.Age = T1.Age
WHERE ISNULL(T1.dteEffectiveDate,T2.dtePrevious) is not null
AND ISNULL(T1.dteNext,T2.dteEffectiveDate) is not null
GO
sorties qui:
Start Date End Date Age Count Start Count End Mid Lives
2009-01-01 2010-01-01 40 300 200 250
2009-01-01 2010-01-01 20 100 50 75
2009-01-01 2010-01-01 30 10 0 5
Il fonctionne parfaitement, mais quand j'exécuter sur les données réelles, soit environ 7 m dossiers, il faut péniblement longue à exécuter.
Quelqu'un at-il des suggestions?
Merci
Karl
La solution
Il est difficile de faire beaucoup de recommandations.
Une chose que je recommanderais est des indices sur ces colonnes que vous utilisez comme clés étrangères dans vos conditions JOIN, par exemple.
-
Age
-
dteEffectiveDate
-
dteNext
Créer un index NONCLUSTERED sur chacune de ces colonnes séparément et mesurer à nouveau. Avec seulement quelques lignes de données, il n'y a pas d'amélioration mesurable - mais avec des millions de lignes, il peut faire une différence
.