2010-07-27 7 views
2

J'ai les suivantes View, appelé ViewGoods:Sélectionnez Délai d'attente avec 2 Paramètres

SELECT  
G.Gid, 
SI.[$Id] AS FirstSiteInId, 
SI.Date AS FirstSiteInDate, 
SI.Comments AS FirstSiteInComments, 
S.[$Id] AS FirstSiteId, 
S.[$Refex] AS FirstSiteRefex, 
SI.Client AS ClientId, 
C.[$Refex] AS ClientRefex, 
CASE WHEN SI.Contract IS NULL THEN (SELECT Contract.[$Id] 
            FROM StockType AS ST 
            INNER JOIN StockTypeContract AS STC ON ST.[$Id] = STC.[$ParentId] 
            INNER JOIN Contract ON STC.Contract = Contract.[$Id] 
            WHERE ST.[$Id] = VGST.StockType 
            AND SI.Date >= STC.StartDate) 
            ELSE SI.Contract END AS Contract, 
CASE WHEN SI.Contract IS NULL THEN (SELECT Contract.[$Refex] 
            FROM StockType AS ST 
            INNER JOIN StockTypeContract AS STC ON ST.[$Id] = STC.[$ParentId] 
            INNER JOIN Contract ON STC.Contract = Contract.[$Id] 
            WHERE ST.[$Id] = VGST.StockType 
            AND SI.Date >= STC.StartDate) 
            ELSE CT.[$Refex] END AS ContractRefex, 
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.SiteId ELSE NULL END AS SiteId, 
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.SiteRefex ELSE NULL END AS SiteRefex, 
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.Lid ELSE NULL END AS Lid, 
ISNULL(W.Weight, VGSA.Weight * Q.Quantity) AS Weight, 
COALESCE (Q.Quantity, 0) AS Quantity, 
VGSA.Article, 
VGSA.ArticleName, 
VGST.StockType, 
VGST.StockTypeRefex 
FROM dbo.Goods AS G 
INNER JOIN dbo.SiteIn AS SI ON G.SiteIn = SI.[$Id] 
INNER JOIN dbo.Client AS C ON C.[$Id] = SI.Client 
INNER JOIN dbo.Site AS S ON SI.Site = S.[$Id] 
LEFT OUTER JOIN dbo.Contract AS CT ON SI.Contract = CT.[$Id] 
LEFT OUTER JOIN dbo.ViewGoodsLocation AS L ON G.Gid = L.Gid 
LEFT OUTER JOIN dbo.ViewGoodsWeight AS W ON G.Gid = W.Gid 
LEFT OUTER JOIN dbo.ViewGoodsQuantity AS Q ON G.Gid = Q.Gid 
LEFT OUTER JOIN dbo.ViewGoodsSingleArticle AS VGSA ON G.Gid = VGSA.Gid 
LEFT OUTER JOIN dbo.ViewGoodsStockType AS VGST ON VGST.Gid = G.Gid 

Lors de l'interrogation qui Voir avec le paramètre Client ou le paramètre Lid, individuellement, tout fonctionne bien. Mais si j'essaie de mélanger les deux, la vue expire sans résultat. Ci-dessous la requête RemettRe le délai d'attente:

SELECT [t0].[Gid], [t0].[FirstSiteInId], [t0].[FirstSiteInDate], [t0].[FirstSiteInComments], [t0].[FirstSiteId], [t0].[FirstSiteRefex], [t0].[ClientId], [t0].[ClientRefex], [t0].[Contract], [t0].[ContractRefex], [t0].[SiteId], [t0].[SiteRefex], [t0].[Lid], [t0].[Weight], [t0].[Quantity], [t0].[Article], [t0].[ArticleName], [t0].[StockType], [t0].[StockTypeRefex] 
FROM [ViewGoods] AS [t0] 
WHERE ([t0].[Lid] IS NOT NULL) AND (([t0].[ClientId]) = 70) 

Où ai-je passé?

EDIT: J'ai inclus ici le plan d'exécution réel http://pastebin.com/PMY0aLE1.

+0

Avez-vous regardé le plan d'exécution de la requête de sélection? Il donnera parfois de bons conseils sur les index manquants – MLT

+1

Je seconde le commentaire de Martin Smith pour échanger les références de vue avec les requêtes réelles qu'elles contiennent, puis optimiser la requête. C'est contre-intuitif d'un point de vue procédural/programmation OO, mais c'est un terrain basé SET ... –

Répondre

2

Depuis le plan de requête que vous avez publié il semble accéder à 10 tables

Article, client, contrat, marchandises, GoodsArticle, GoodsEvent, Site, SiteIn, StockType, StockTypeContract

Sont-ils tous ces réellement nécessaire pour vos résultats ou est-ce que l'un d'entre eux n'est qu'un artefact d'être dans une perspective à laquelle vous vous joignez?

Il y a 25 nœuds racine dans le plan pour ces 10 tables, donc certaines tables sont accédées plus d'une fois et cela semble être un gaspillage.

Vous pouvez voir dans cette partie du plan (ajoute jusqu'à 40% du coût) GoodsEvent semble être consulté trois fois. Je suis assez sûr que si vous vous débarrassez des points de vue que vous serez en mesure de consolider cela.

Portion of plan http://img245.imageshack.us/img245/4105/executionplan.png

Je pense à l'heure actuelle ce bit du plan est en train de faire quelque chose comme ça

SELECT Query3.Gid, Query3.SiteId, Query3.Lid, Query3.Expr1017 
FROM 
(
SELECT 
    Gid, 
    SUM(CASE WHEN Type ='SO' THEN -Quantity ELSE Quantity END) AS Expr1017 
FROM GoodsEvent 
WHERE Type IN('AQ','SI','SO') AND IsDeleted = 0 
GROUP BY Gid 
) Query1 
JOIN 
(
SELECT 
    Gid, 
    MAX(EventOn) AS Expr1014 
FROM GoodsEvent 
WHERE IsDeleted = 0 
GROUP BY Gid 
) Query2 ON Query1.GID = Query2.GID 
JOIN 
(
SELECT 
GoodsEvent.Gid, 
GoodsEvent.EventOn, 
GoodsEvent.SiteId, 
GoodsEvent.Lid 
FROM GoodsEvent WHERE IsDeleted = 0 
) Query3 ON Query3.gid=Query2.gid AND Query3.EventOn = Query2.Expr1014 

Il pourrait être intéressant de tester si cela est sémantiquement équivalent et exécute mieux

;WITH X AS 
(
SELECT Gid, 
     SiteId, 
     Lid, 
     RANK() OVER (PARTITION BY Gid ORDER BY EventOn DESC) AS RN, 
     Type 
FROM GoodsEvent 
WHERE IsDeleted = 0 
) 
SELECT Gid,SiteId, Lid, 
     SUM(CASE WHEN Type ='SO' THEN -Quantity ELSE Quantity END) 
     OVER(PARTITION BY Gid) AS Expr1017, 
FROM X WHERE RN=1 AND Type IN('AQ','SI','SO') 
+0

Que me suggérez-vous de faire? Ces vues sont appelées car elles filtrent les informations sur les biens disponibles pour les clients et les événements qu'ils ont générés. – Hallaghan

+1

Nous vous proposons d'arrêter d'utiliser la période vue. – HLGEM

+0

@Hallaghan Au moment où le plan de requête est extrêmement complexe. Je soupçonne que si vous commencez juste à nouveau et écrire la requête contre les tables de base, vous serez en mesure de simplifier les choses beaucoup. Sans connaître vos données et ce que la sémantique souhaitée est difficile pour moi de suggérer des améliorations spécifiques. –

0

Uh oh ......

je peux voir dans votre définition de la vue que vous joindrez à au moins 9 autres structures de données, qui semblent être vues aussi bien (donc il pourrait y avoir plus jointures de table dans ceux-ci).

Ce n'est probablement pas la réponse que vous allez vouloir entendre, mais si vous avez besoin de joindre ces nombreuses structures de données, alors quelque chose s'est mal passé au moment du design. Je suggère de revenir à la planche à dessin et de repenser la conception de cette base de données.

Edit: pensées supplémentaires ..

Considérez que lorsque vous effectuez des requêtes qui nécessitent régulièrement vous joindre à plusieurs tables, ce sont des candidats à des vues indexées matérialisées à savoir les structures, qui sont effectivement des tables. L'exécution régulière d'un grand nombre d'opérations de jointure entraîne des requêtes médiocres avec une évolutivité limitée. Gardez à l'esprit que la normalisation est le point de départ pour une bonne conception de la base de données, elle ne doit pas nécessairement être votre point de terminaison.

+0

Eh bien, je n'ai pas conçu cette vue ou le projet tout à fait, je suis juste bug corrigeant cette application en utilisant cette base de données. Retourner à la planche à dessin n'est plus une option ici, au moins ils le disent. – Hallaghan

+2

Je ne suis pas d'accord - joindre si nécessaire, car c'est ce qui est requis dans une base de données normalisée. Mais la superposition des vues les unes sur les autres est certainement une recette pour une performance et une maintenance médiocres - une bonne prise là-bas. –

+0

Je suis d'accord avec vous Poneys, mais je ne suis pas le responsable ici. Je peux seulement faire ce qu'on me dit. Je donne juste la maintenance à l'application. – Hallaghan

1

Les vues ne doivent jamais référencer d'autres vues si vous souhaitez obtenir des performances. C'est juste dehors et hors conception pauvre. Vous ne devriez pas utiliser une vue pour le faire. Lorsque vous faites cela, il doit matérialiser complètement ces vues avant de pouvoir créer l'ensemble d'enregistrements. Donc, pour peut-être 200 dossiers finaux, vous devrez peut-être appeler plusieurs milliards. Cela va ralentir énormément les choses et j'ai constaté que lorsque les gens utilisent cette technique, si vous suivez les points de vue tout en bas, vous appelez souvent les mêmes données de la même table plusieurs fois. N'utilisez PAS une vue de cette façon. Si vous devez utiliser une vue, accédez directement aux tables et n'appelez pas d'autres vues. C'est une route que vous ne voulez pas descendre, nous avons presque perdu un client $ mulimillion parce que quelqu'un a conçu de cette façon au lieu d'utiliser de bonnes méthodes d'accès aux données.

Ceci est une garantie, aucun moyen de résoudre ce problème de performance qui entraînera l'arrêt brutal de votre base de données. C'est une période de conception MAUVAISE et doit être des changements dès que humainement possible.

Questions connexes