2010-02-02 5 views
0

J'ai cette requête SQL mais son fonctionnement soo lent,optimize cette requête SQL

SELECT 
    wr.wr_re_id as ReID, 
    sum(wr.wr_total) as PRTotal 
FROM 
    Workorder2 w 
    INNER JOIN 
    Workorder_Row2 wr ON wr.wr_wo_id = w.wo_id 
WHERE 
    (w.wo_type = 1 or w.wo_type = 2) 
    AND wr.wr_row_type = 2 
    AND w.wo_lo_id like '%' 
    AND w.wo_date_time >= '2010-01-01' 
    AND w.wo_date_time <= '2010-01-31' 
    AND wr.wr_wo_id IN 
     (SELECT 
      wr2.wr_wo_id 
     FROM 
      Workorder_Row2 wr2 
      INNER JOIN Workorder2 w2 ON w2.wo_id = wr2.wr_wo_id 
      AND w2.wo_date_time >= '2010-01-01' 
      AND w2.wo_date_time <= '2010-01-31' 
     WHERE 
      wr2.wr_row_type = 1) 
GROUP BY 
    wr.wr_re_id 

des conseils que je peux accélérer? cela prend presque 1 minute à exécuter.
Je pense que le problème est avec le AND wr.wr_wo_id IN (SELECT ... mais j'ai besoin de cela pour savoir s'il y a des ventes de produits sur le même workorder qui contient une menace.

+1

La première étape devrait être d'obtenir le plan de requête à partir de votre base de données, cela vous montrera où de longues analyses de table se produisent. – Paolo

+0

'ET w.wo_lo_id comme '%'' semble mortel pour moi – Natrium

+0

@Natrium cette déclaration est fondamentalement dire w.wo_lo_id peut être n'importe quoi, même "", mais pas NULL. J'espère que l'optimiseur de requêtes l'attrape. –

Répondre

2

Tout d'abord, jetez un coup d'œil à votre plan d'exécution. Il est difficile pour nous de l'optimiser car nous ne connaissons pas vos données.

La chose qui saute le plus est la pièce wr.wr_wo_id IN (SELECT...). Ce serait beaucoup plus efficace comme une jointure, comme ceci:

SELECT wr.wr_re_id as ReID, sum(wr.wr_total) as PRTotal 
FROM Workorder2 w 
    INNER JOIN Workorder_Row2 wr on wr.wr_wo_id = w.wo_id 
    INNER JOIN (
     SELECT DISTINCT wr2.wr_wo_id 
     FROM Workorder_Row2 wr2 
      INNER JOIN Workorder2 w2 on w2.wo_id = wr2.wr_wo_id 
     WHERE w2.wo_date_time >= '2010-01-01' 
      AND w2.wo_date_time <= '2010-01-31' 
      AND wr2.wr_row_type = 1 
    ) T ON T.wr_wo_id = wr.wr_wo_id 
WHERE (w.wo_type = 1 or w.wo_type = 2) 
    AND wr.wr_row_type = 2 
    AND w.wo_lo_id like '%' 
    AND w.wo_date_time >= '2010-01-01' AND w.wo_date_time <= '2010-01-31' 
GROUP BY wr.wr_re_id 

Il est utile de considérer si cela aiderait à ajouter des indices. Cela dépend de la fréquence de mise à jour/insertion/suppression de ces tables et de la sélectivité de chaque colonne.

COMPLEMENTAIRES:

Pour faire l'inverse, à savoir remplacer WHERE wr.wr_wo_id NOT IN (SELECT...), vous utilisez:

SELECT wr.wr_re_id as ReID, sum(wr.wr_total) as PRTotal 
FROM Workorder2 w 
    INNER JOIN Workorder_Row2 wr on wr.wr_wo_id = w.wo_id 
    LEFT JOIN (
     SELECT DISTINCT wr2.wr_wo_id 
     FROM Workorder_Row2 wr2 
      INNER JOIN Workorder2 w2 on w2.wo_id = wr2.wr_wo_id 
     WHERE w2.wo_date_time >= '2010-01-01' 
      AND w2.wo_date_time <= '2010-01-31' 
      AND wr2.wr_row_type = 1 
    ) T ON T.wr_wo_id = wr.wr_wo_id 
WHERE T.wr2.wr_wo_id IS NULL 
    AND (w.wo_type = 1 or w.wo_type = 2) 
    AND wr.wr_row_type = 2 
    AND w.wo_lo_id like '%' 
    AND w.wo_date_time >= '2010-01-01' AND w.wo_date_time <= '2010-01-31' 
GROUP BY wr.wr_re_id 

Cependant, il est plus facile à lire et (je suppose, essayer si elle) plus efficace utiliser:

SELECT wr.wr_re_id as ReID, sum(wr.wr_total) as PRTotal 
FROM Workorder2 w 
    INNER JOIN Workorder_Row2 wr on wr.wr_wo_id = w.wo_id 
WHERE (w.wo_type = 1 or w.wo_type = 2) 
    AND wr.wr_row_type = 2 
    AND w.wo_lo_id like '%' 
    AND w.wo_date_time >= '2010-01-01' AND w.wo_date_time <= '2010-01-31' 
    AND NOT EXISTS (
     SELECT NULL 
     FROM Workorder_Row2 wr2 
      INNER JOIN Workorder2 w2 on w2.wo_id = wr2.wr_wo_id 
     WHERE w2.wo_date_time >= '2010-01-01' 
      AND w2.wo_date_time <= '2010-01-31' 
      AND wr2.wr_row_type = 1 
      AND wr2.wr_wo_id = wr.wr_wo_id 
    ) 
GROUP BY wr.wr_re_id 
+0

Merci! Cela a aidé beaucoup! je viens de découvrir sur le plan d'exécution désolé de ne pas l'inclure J'ai le même problème avec wr.wr_wo_id PAS DANS (SELECT ..). Serait-ce le même que: ) T ON T.wr_wo_id <> wr.wr_wo_id – Alexander

+0

désolé de sauter aux conclusions! mais ce n'était pas la bonne réponse. la requête ci-dessus ne retourne pas le même résultat que lorsque j'utilise l'instruction IN (SELECT ...). – Alexander

+1

Etes-vous sûr? Je pourrais manquer quelque chose d'évident, mais ils me semblent équivalents. En quoi les résultats diffèrent-ils? – Paul

0

Chaque moteur de base de données SQL dispose d'un analyseur de requêtes qui vous aidera à comprendre pourquoi il est lent. Mais dans ce cas, la solution est probablement aussi simple que la création d'index sur ces colonnes:

  • Workorder2.wo_id
  • Workorder_Row2.wr_wo_id

Essayez d'ajouter ces index comme index clusterisés. Si cela ne fonctionne pas, vérifiez l'analyseur de requêtes pour d'autres idées.

  • Dans SQL Server cela se trouve dans le Management Studio en entrant votre requête dans la fenêtre de requête et en cliquant sur les boutons « Affichage plan d'exécution estimé » et « Analyser la requête dans la base de données Tuning Advisor »
  • En MySQL peut utiliser la commande EXPLAIN

Remarque: Ne vous inquiétez pas pour votre section "IN (SELECT ...)". Ce sera aussi efficace qu'une jointure sur n'importe quel moteur de base de données moderne.

+0

Merci RobC, je vais regarder dans ce. Cela nécessiterait un changement de base de données d'une sorte je deviner? – Alexander