2012-10-19 13 views
1

J'ai une requête SQL que je veux optimiser en tant que requête interne d'un SP.Optimisation d'une requête SQL

SELECT TOP 1 @CurrentStartDate = Strt_Dt FROM (
SELECT 1 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'INPR' 
    UNION 
    SELECT TOP 1 2 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'CMPL' 
    ORDER BY enddate DESC 
    UNION 
    SELECT TOP 1 3 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'PLND' 
    ORDER BY strt_dt 
    UNION 
    SELECT 4 AS seq, 'UNP', NULL, NULL, NULL, tckt_id, 'Unplanned' 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID 
) aa 
ORDER BY aa.seq 

Existe-t-il une meilleure façon d'utiliser cette requête? J'ai besoin de cela car j'ai beaucoup de logique ayant le même type.

+0

La première sous-requête devrait-elle avoir une clause 'ORDER BY'? Est-ce que la dernière sous-requête devrait avoir une clause WHERE supplémentaire, sinon elle semble inclure tous les enregistrements inclus dans les requêtes précédentes? Et pouvez-vous montrer quelques données pour clarifier ce qui est et ce qui n'est pas exclu en utilisant ces «TOP 1»? – MatBailie

+0

*** SQL *** est juste le * Structured Query Language * - une langue utilisée par de nombreux systèmes de bases de données, mais pas un produit de base de données ... optimisations sont très spécifiques au vendeur - nous avons donc vraiment besoin de savoir quelle ** base de données système ** (et quelle version) vous utilisez .... –

+0

Il serait également utile d'ajouter ce que vous essayez d'obtenir en anglais - il est plus facile d'aider et de résoudre un problème si vous l'expliquez. Qu'est-ce que la requête est censée faire, qu'est-ce qu'elle ne fait pas? Quels sont les problèmes de performance? (Je suppose que les UNIONS sont le problème principal) – Charleh

Répondre

2

Vous effectuez une union sur 4 résultats de la même table pour les mêmes critères, ne pouvez-vous pas simplement utiliser une instruction CASE? par exemple.

SELECT 
    CASE Stat 
     WHEN 'INPR' THEN 1 
     WHEN 'CMPL' THEN 2 
     WHEN 'PLND' THEN 3 
     WHEN 'Unplanned' THEN 4 
     ELSE 0 -- Not sure what your 'ELSE' case would be 
    END as Seq, 
    etc.... 
FROM pipeline_rest_envr_info e 
WHERE e.tckt_id = @TicketID 

Vous aurez toujours besoin des déclarations de cas pour tous les domaines qui ont une logique, mais il comprendra toutes les données et sera beaucoup plus facile à lire. Devrait également être beaucoup mieux pour la performance.

+0

Sous-requête on n'a pas un ORDER BY, sous-interroger deux ordres par 'end_dt', sous-interroger trois ordres par' strt_dt'. Cette réponse ne tient pas compte de cet aspect. Pourtant;) – MatBailie

+0

D'accord - bien que je pense qu'il est difficile de voir ce que l'OP obtenait avec la requête originale, donc je ne suis toujours pas sûr si c'est une solution qui peut prendre en compte ce qui est nécessaire – Charleh

+0

* S'il existe un enregistrement "En cours", renvoyez la date de début. Sinon, retournez la date de début de la dernière pour compléter l'enregistrement 'Completed'. Sinon, retournez le début du suivant pour démarrer les enregistrements 'Planned'. Sinon, renvoyez 'NULL'. – MatBailie

2
SELECT TOP 1 @CurrentStartDate = Strt_Dt FROM (
SELECT 
     CASE stat WHEN 'INPR' THEN 1 
        WHEN 'CMPL' THEN 2 
        WHEN 'PLND' THEN 3 
        ELSE 4 END AS seq , 
     Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID) aa 
ORDER BY aa.seq 

En fait, il est la même réponse que @Charleh

vous n'avez pas besoin deuxième et troisième TOP 1 parce que vous prenez seul le premier de toute union

+1

Sous-requête on n'a pas un ORDER BY, sous-interroger deux ordres par 'end_dt', sous-interroger trois ordres par' strt_dt'. Cette réponse ne tient pas compte de cet aspect. Pourtant,) – MatBailie

+0

Oui, merci, je n'ai pas vu 'ORDER BY enddate DESC' et' ORDER BY strt_dt' dans ce cas je pense que le vôtre est la meilleure méthode, c'est facile à comprendre [et c'est un point de vue solide] – Zyku

+0

Vous voulez dire que vous pensez que les OP sont les meilleurs? * (J'ai posté un commentaire demandant plus de détails, mais pas de réponse.) * – MatBailie

0

Je pense que vous devriez avoir à faire Temp Table qui est indexée comme vous le souhaitez, puis insère des enregistrements dans chaque UNION s. C'est un peu plus rapide que l'utilisation de UNION s.

2

Je l'absence de réponse à mon commentaire, je vais faire quelques hypothèses ...

Un seul tckt_id peut avoir:

  • multiples CMPL articles. (Complété?)
  • Juste un INPR article. (En cours?)
  • Plusieurs articles PLND articles. (Prévu?)
  • Plusieurs autres articles. (Unplanned?)


Vous voulez que le strt_dt de ...

  • L'élément INPR, si elle existe.
  • Sinon, le dernier élément CMPL, s'il existe. Sinon, le premier élément PLND, s'il existe.
  • Sinon, NULL


SELECT 
    TOP 1 
    @current_start_date 
    = 
    CASE WHEN stat = 'INPR' THEN MIN(strt_dt) 
     WHEN stat = 'CMPL' THEN MAX(strt_dt) 
     WHEN stat = 'PLND' THEN MIN(strt_dt) 
          ELSE NULL 
    END 
FROM 
    pipeline_rest_envr_info 
WHERE 
    tckt_id = @TicketID 
GROUP BY 
    stat 
ORDER BY 
    CASE WHEN stat = 'INPR' THEN 1 
     WHEN stat = 'CMPL' THEN 2 
     WHEN stat = 'PLND' THEN 3 
          ELSE 4 END 


Cela n'a une hypothèse supplémentaire:

  • Quelle que soit CMPL article terminé dernier, a également commencé la dernière

Si cette hypothèse est fausse, et si vous avez accès à ROW_NUMBER(), vous pouvez essayer cette place ...

WITH 
    plus_sort_order 
(
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY stat ORDER BY strt_dt ASC) AS order_strt, 
    ROW_NUMBER() OVER (PARTITION BY stat ORDER BY end_dt DESC) AS order_end, 
    * 
    FROM 
    pipeline_rest_envr_info 
    WHERE 
    tckt_id = @TicketID 
) 
SELECT 
    TOP 1 
    @current_start_date = strt_dt 
FROM 
    plus_sort_order 
WHERE 
    (order_strt = 1) OR (stat = 'CMPL' AND order_end = 1) 
ORDER BY 
    CASE WHEN stat = 'INPR' THEN 1 
     WHEN stat = 'CMPL' THEN 2 
     WHEN stat = 'PLND' THEN 3 
          ELSE 4 END 

Il y a pas mal d'autres façons. Mais beaucoup dépend de vos données. Je vous conseille de jouer avec les idées ici et dans d'autres réponses, et d'utiliser des plans d'explication/de requête pour déterminer les index dont vous avez besoin pour chaque option disponible.