2010-08-04 5 views
0

Je dois interroger le tableau des commandes pour obtenir le décompte de toutes les commandes pour les transactions d'hier, groupées par date d'expédition. Ensuite, j'ai besoin d'une colonne supplémentaire pour donner le total des commandes pour la date d'expédition pour toutes les transactions. Lorsque j'ai ajouté cette deuxième colonne, le temps de traitement a augmenté exponentiellement (ce qui était attendu) à 109s. Est-ce que je pourrais améliorer ce SQL? Je veux juste savoir s'il me manque quelque chose de fondamental ici.Aide à l'optimisation des requêtes Oracle - Multi-passes

SELECT t.shipping_date 
     , t.net_orders 
     , count(*) as total_orders 
FROM (
    SELECT s.store_num 
      , s.store_cd 
      , to_char(o.shipping_date, 'MM/DD/YYYY') as shipping_date 
      , COUNT (*) as net_orders 
    FROM order o left 
      join store s 
       on (s.store_num = o.store_num) 
    WHERE TRUNC (o.order_date) = TRUNC (SYSDATE - 1) 
    AND s.store_cd = 'ZZZ' 
    AND o.status in ('A', 'B') 
    GROUP BY s.store_num 
      , s.store_cd 
      , to_char(shipping_date, 'MM/DD/YYYY') 
) t 
LEFT JOIN order o ON 
      (TRUNC (o.shipping_date) = to_date(t.shipping_date, 'MM/DD/YYYY') 
      and o.store_num = t.store_num) 
WHERE o.status in ('A', 'B') 
GROUP BY t.shipping_date, t.net_orders; 

Je index sur les toutes ces colonnes, en plus des expressions suivantes: TRUNC (ORDER_DATE) et TRUNC (shipping_date).

+0

Veuillez préciser à partir de quelle (s) table (s) les champs 'shipping_date' et' order_date' (requête interne). – ThinkJet

+0

J'ai modifié le code SQL ci-dessus selon votre demande. Merci. – Bradford

Répondre

1

Je re-écrit votre requête comme:

SELECT t.shipping_date, 
      t.net_orders, 
      COUNT(*) as total_orders 
    FROM (SELECT s.store_num, 
        s.store_cd, 
        o.status, 
        TRUNC(o.shipping_date) AS shipping_date, 
        COUNT (*) as net_orders 
      FROM STORE s 
      JOIN ORDER o ON o.store_num = s.store_num 
         AND o.status IN ('A', 'B') 
      WHERE s.store_cd = 'ZZZ' 
       AND TRUNC(order_date) = TRUNC (SYSDATE - 1) 
    GROUP BY s.store_num, s.store_cd, TRUNC(shipping_date)) t 
LEFT JOIN ORDER o ON TRUNC(o.shipping_date) = t.shipping_date 
       AND o.store_num = t.store_num 
       AND o.status = t.status 
GROUP BY t.shipping_date, t.net_orders; 

Certains réagencement mineures, mais je ne me débarrasser de la TO_CHAR (shipping_date) qui est reconvertie plus tard à une date. TRUNC(shipping_date) est le même, et simplifie l'opération.

L'adhésion à des critères utilisant des fonctions n'utilisera pas d'index - vous devrez créer un index basé sur une fonction correspondant aux critères JOIN.

+0

Merci, OMG Ponies. Cette requête retourne maintenant en 0.78s. Juste pour être sûr, l'accélération était-elle due à la dernière jointure, où vous avez transformé la contrainte where en une partie de la contrainte de jointure? – Bradford

+0

@ Bradford: Oui - la conversion à différents types de données va certainement nuire aux performances, en particulier lorsque vous souhaitez vous joindre à cette information. –

3

Si vous êtes à la recherche d'une sortie comme:

shipping_date  net_orders  total_orders 
01-AUG-2004  14    37 
02-AUG-2004  17    29 
03-AUG-2004  19    43 

Que diriez-vous juste:

SELECT * 
    FROM (
    SELECT TRUNC(o.shipping_date) as shipping_date 
     , COUNT(CASE WHEN TRUNC(o.order_date) = TRUNC(SYSDATE - 1) 
         THEN 1 
         ELSE NULL 
        END) as net_orders -- count does not count NULL values. 
     , COUNT(*) as total_orders 
     FROM order o 
      LEFT JOIN 
      store s 
       on s.store_num = o.store_num 
    WHERE s.store_cd = 'ZZZ' 
     AND o.status in ('A', 'B') 
    GROUP BY TRUNC(o.shipping_date) 
    ) 
WHERE net_orders > 0 -- only shipping dates that had at least one order yesterday 

Il va éviter le supplément rejoindre à la table des commandes et puisque vous allez pour avoir à toucher toutes les commandes du magasin de toute façon, pendant que vous obtenez le nombre total, vous pouvez aussi faire ce que j'appellerais un compte conditionnel en même temps.

+0

Oui, mais cela me montrerait toutes les dates d'expédition. Je veux seulement montrer les dates d'expédition qui se sont produites pour les commandes d'hier. – Bradford

+0

Désolé j'ai oublié cela. J'ai mis à jour le code afin que seules les dates d'expédition avec au moins une commande pour hier soient retournées. –