2010-09-28 34 views
2

HI TousSQL Server 2008 Optimize FULL JOIN avec les déclarations de isNull

J'espérais que quelqu'un pourrait me aider à améliorer une requête que je dois exécuter périodiquement. Pour le moment, il faut plus de 40 minutes pour l'exécuter. Il utilise la totalité de la mémoire allouée pendant ce temps, mais l'utilisation du processeur est généralement de 2% à 5%, de temps en temps de 40% pendant quelques secondes.

Je possède 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. De plus, chacun a un dtePrevious et dteNext, qui reflète les dates de la date d'entrée en vigueur précédente/suivante la plus proche. Maintenant, ce que je veux, c'est une requête qui va calculer la valeur moyenne sur les champs de comptage entre les périodes successives, dans un âge spécifique.

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 30 ans a seulement une entrée, 10. Ceci est à 2009/01/01. Il n'y a aucune entrée au 2010/01/01, mais nous savons que les données ont été saisies à ce moment-là, donc le fait qu'il n'y ait rien signifie que 30 est 0 à cette date. Par conséquent, la requête devrait produire 5.

Pour ce faire, j'utilise un FULL JOIN de la table sur lui-même, et utilise 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 

qui sort:

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

+0

Quels index avez-vous sur la table? Y a-t-il un maximum de 2 lignes par âge? –

+0

Aucun indice. Il n'y aura qu'une seule entrée par âge par dteEffectiveDate. Donc, selon le nombre de dates d'entrée en vigueur, il n'y a pas de limite au nombre de fois qu'un âge se présente. Mais il y aura toujours une seule combinaison de dteEffectiveDate, dtePrevious et dteNext pour chaque âge.(Ceci est simplifié, dans le vrai problème que je divise à travers beaucoup plus de champs) – Karl

Répondre

2

Il est difficile de faire beaucoup de recommandations.

Une chose que je recommanderais certainement, ce sont les index sur les 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 quelques lignes de données, aucune amélioration n'est mesurable - mais avec des millions de lignes, cela peut faire la différence.