web-dev-qa-db-fra.com

Joindre à une variable @Table est en cours d'exécution inédiction

D'accord, j'ai donc une procédure stockée de rapport qui fonctionnait incroyablement lente. Les clients se plaignaient que le rapport ne fonctionnerait pas, j'ai commencé à étudier exactement où dans la procédure stockée, le problème était et j'ai trouvé cette partie de 99,8% du temps.

DECLARE @xmlTemp TABLE (
  CompanyID  INT,
  StoreID    INT,
  StartDate  DATETIME,
  DateStaID  INT,
  EndDate    DATETIME,
  DateEndID  INT,
  LastUpdate DATETIME)

INSERT INTO @xmlTemp
VALUES      (50,
             2,
             '3/3/2013',
             0,
             '3/3/2013',
             0,
             '3/3/2013')

SELECT DISTINCT T.CompanyID,
                CompanyName,
                Z.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                Total - Isnull((SELECT Sum(DISTINCT PaymentAmount)
                                FROM   vPullDrawerPayments
                                WHERE  CompanyID = T.CompanyID
                                       AND StoreID = T.StoreID
                                       AND TransactionID = T.TransactionID
                                       AND Isnull(PaymentType, 1) <> 1), 0) AS PaymentAmount,
                'Cash'                                                      AS PaymentDesc,
                CASE
                  WHEN Z.EndDate >= Z.LastUpdate THEN 1
                  ELSE 0
                END                                                         AS MissingData
FROM   vPullDrawerPayments AS T
       INNER JOIN @xmlTemp AS Z
         ON T.CompanyID = Z.CompanyID
            AND T.StoreID = Z.StoreID
WHERE  BusinessDate BETWEEN Z.StartDate AND Z.EndDate
UNION ALL
SELECT DISTINCT NC.CompanyID,
                CompanyName,
                Z.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                PaymentAmount,
                PaymentDesc,
                CASE
                  WHEN Z.EndDate >= Z.LastUpdate THEN 1
                  ELSE 0
                END AS MissingData
FROM   vPullDrawerPayments AS NC
       INNER JOIN @xmlTemp AS Z
         ON NC.CompanyID = Z.CompanyID
            AND NC.StoreID = Z.StoreID
WHERE  BusinessDate BETWEEN Z.StartDate AND Z.EndDate
       AND Isnull(PaymentType, 1) <> 1
UNION ALL
SELECT DISTINCT C.CompanyID,
                CompanyName,
                Z.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                Sum(Abs(LineAmount)) AS PaymentAmount,
                'Coupons'            AS PaymentDesc,
                CASE
                  WHEN Max(Z.EndDate) >= Max(Z.LastUpdate) THEN 1
                  ELSE 0
                END                  AS MissingData
FROM   vPullDrawerPayments AS C
       INNER JOIN @xmlTemp AS Z
         ON C.CompanyID = Z.CompanyID
            AND C.StoreID = Z.StoreID
WHERE  BusinessDate BETWEEN Z.StartDate AND Z.EndDate
GROUP  BY C.CompanyID,
          CompanyName,
          Z.StoreID,
          StoreName,
          CashedOutBy,
          TransactionID,
          RegisterID,
          BusinessDate,
          CashedOut 

La partie @XMLTEpp de cette requête est normalement utilisée pour prendre des paramètres de notre application Web et les transformer en paramètres que le rapport peut réellement utiliser. Par souci de test, je ne fais que insérer des valeurs qui exécutent ceci pour un magasin pendant une journée. Exécution de cette partie peut prendre 20 minutes.

J'ai donc exécuté ce plan de requête via Planexplorer et a vu qu'il traitait toutes les données de deux de mes tables de fait au lieu de filtrer ce magasin et ce jour-là. Comme on le voit dans l'image ci-dessous.

QueryPlan Évidemment c'est mauvais. Donc, la prochaine étape que j'ai prise est de décrocher la jointure The @xml Temp et de placer manuellement les valeurs de la clause de la requête WHERE pour voir à quel point cela a fonctionné.

SELECT DISTINCT T.CompanyID,
                CompanyName,
                T.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                Total - Isnull((SELECT Sum(DISTINCT PaymentAmount)
                                FROM   vPullDrawerPayments
                                WHERE  CompanyID = T.CompanyID
                                       AND StoreID = T.StoreID
                                       AND TransactionID = T.TransactionID
                                       AND Isnull(PaymentType, 1) <> 1), 0) AS PaymentAmount,
                'Cash'                                                      AS PaymentDesc
--CASE WHEN Z.'3/3/2013' >= Z.LastUpdate THEN 1 ELSE 0 END AS MissingData
FROM   vPullDrawerPayments AS T
WHERE  CompanyID = 50
       AND StoreID = 1
       AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
UNION ALL
SELECT DISTINCT NC.CompanyID,
                CompanyName,
                NC.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                PaymentAmount,
                PaymentDesc
--CASE WHEN Z.'3/3/2013' >= Z.LastUpdate THEN 1 ELSE 0 END AS MissingData
FROM   vPullDrawerPayments AS NC
WHERE  CompanyID = 50
       AND StoreID = 1
       AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
       AND Isnull(PaymentType, 1) <> 1
UNION ALL
SELECT DISTINCT C.CompanyID,
                CompanyName,
                C.StoreID,
                StoreName,
                CashedOutBy,
                TransactionID,
                RegisterID,
                BusinessDate,
                CashedOut,
                Sum(Abs(LineAmount)) AS PaymentAmount,
                'Coupons'            AS PaymentDesc
--CASE WHEN MAX(Z.'3/3/2013') >= MAX(Z.LastUpdate) THEN 1 ELSE 0 END AS MissingData
FROM   vPullDrawerPayments AS C

WHERE  CompanyID = 50
       AND StoreID = 1
       AND BusinessDate BETWEEN '3/3/2013' AND '3/3/2013'
GROUP  BY C.CompanyID,
          CompanyName,
          C.StoreID,
          StoreName,
          CashedOutBy,
          TransactionID,
          RegisterID,
          BusinessDate,
          CashedOut 

En modifiant cela sur une simple clause où il fonctionne en 4 secondes au lieu de 20 minutes et plus. De plus, le plan de requête montre que le bon est-il une raison pour laquelle je devrais voir ce comportement?

Modifier ici est le lien complet vers le Queryplan .

5
Zane

[Copier de - ma réponse sur sqlperformance.com .]

Quelques grandes suggestions initiales de discussions ailleurs:

  1. Essayez de créer @XMLTemp comme une table #Temp avec un index en cluster sur (startdate, enddate) au lieu d'une variable de table. Cela peut fournir à SQL Server avec des informations de statistiques plus précises (bien que utiles utiles si la table n'a qu'une ligne).
  2. Si @xmltemp n'a qu'une seule ligne toujours , utilisez deux variables au lieu d'une table en premier lieu.
  3. Essayez d'ajouter l'option (recompiler) à l'instruction, surtout si vous convertiez en variables au lieu de la table #TEpp (paramètre reniflant).
  4. Essayez d'utiliser l'option (MaxDop 1) - le parallélisme est définitivement utilisé et à l'extrémité inférieure, les threads semblent partiellement déséquilibrés. Je me demande si le parallélisme aide ou blesser ici - ne peut pas faire mal à tester la durée avec et sans.
  5. Vous devrez peut-être effectuer des mises à jour statistiques plus rigoureuses. Beaucoup de ces estimations sont beaucoup, bien.
  6. Retirez les distincts. Pour cet ensemble de colonnes, je trouve difficile de croire que cela élimine les doublons, mais l'optimiseur doit fonctionner comme s'il ya des hauts de remise.
  7. Envisagez d'utiliser des paramètres valorisés de table (TVPS) au lieu de déchiqueter XML pour les différentes entreprises/magasins.
5
Aaron Bertrand