Optymalizacja zapytania

Odpowiedz Nowy wątek
2014-12-19 20:38
0

Witam, mam taki problem, robie dosc zlozone zapytanie i w cześci WHERE musialem zamienic AND na OR. Z AND zapytanie wykonywalo sie kilka minut, natomiast z OR ten czas to ponad 2h. W jaki sposob zoptymalizowac zapytanie, zeby wykonalo sie rowniez w pare minut (danych jest bardzo duzo)? Prosze o wszelkie pomysly jak to zrobic.

 
SELECT  DISTINCT  e.umowa,b.statum,b.wartof,a.stid,a.statst,a.grupa,a.wartosc, 
         COALESCE(pd.sumpd, 0) AS sumpd, COALESCE(npd.sumnpd, 0) AS sumnpd, COALESCE(inne.sumin, 0) AS sumin , 
         (a.wartosc -  COALESCE(pd.sumpd, 0) - COALESCE(npd.sumnpd, 0) - COALESCE(inne.sumin, 0)) AS roznica
 
FROM ((((((DROLEASEF2.PLST01PF a INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)  
        INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)                   
        INNER JOIN DROLEASEF2.plfk09pf e ON e.umowa = b.umowa)                   
        INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr AND                
                                                          e.ipoz = f.poznbr)                 
 
LEFT  JOIN
 
               (SELECT e.umowa,b.statum,b.wartof,a.stid,a.statst,a.grupa,a.wartosc,
                         SUM(f.winien - f.ma)  AS sumpd
 
                 FROM ((((DROLEASEF2.plst01pf a INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)   
                   INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)                                                       
                   INNER JOIN DROLEASEF2.plfk09pf e ON e.umowa = b.umowa)                   
                   INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr AND                
                                                                      e.ipoz = f.poznbr)                 
                 WHERE e.invid < 0 AND f.acc1 = '03081' AND 
                           EXISTS(SELECT g.stid, g.invid FROM DROLEASEF2.plst31pf g WHERE e.invid = g.invid AND      
                                    g.stid = a.stid AND g.invid <0) 
                  GROUP BY e.umowa,b.statum,b.wartof,a.stid,a.statst, a.grupa,a.wartosc)  pd
 
ON pd.umowa = e.umowa AND pd.stid = a.stid)
 
LEFT JOIN
 
           (SELECT e.umowa,b.statum,b.wartof,a.stid,a.statst,a.grupa,a.wartosc,
                      SUM(f.winien - f.ma)  AS sumnpd
 
                FROM ((((DROLEASEF2.plst01pf a INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)   
                   INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)                        
                   INNER JOIN DROLEASEF2.plfk09pf e ON b.umowa = e.umowa)                   
                   INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr AND                
                                                                      e.ipoz = f.poznbr) 
                  WHERE  f.acc1 = '03081' AND e.invid < 0 AND NOT EXISTS (SELECT g.stid, g.invid FROM DROLEASEF2.plst31pf g WHERE e.invid =  
                             g.invid AND g.stid = a.stid AND g.invid <0) 
                  GROUP BY e.umowa,b.statum,b.wartof,a.stid,a.statst, a.grupa,a.wartosc)  npd
 
ON npd.umowa = e.umowa AND npd.stid = a.stid)
 
LEFT JOIN
 
     (SELECT e.umowa,b.statum,b.wartof,a.stid,a.statst,a.grupa,a.wartosc,
                      SUM(f.winien - f.ma)  AS sumin
 
                FROM (((((DROLEASEF2.plst01pf a INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)   
                   INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)                        
                   INNER JOIN DROLEASEF2.plfk09pf e ON b.umowa = e.umowa)                   
                   INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr AND                
                                                                       e.ipoz = f.poznbr) 
                  INNER JOIN DROLEASEF2.plfk07pf g ON g.docnbr = f.docnbr AND
                                                                      g.poznbr = f.poznbr)
                  WHERE  f.acc1 = '03081' AND g.zaptyp NOT IN (-1, -3, -4) AND e.invid < 0 
                  GROUP BY e.umowa,b.statum,b.wartof,a.stid,a.statst,               
                               a.grupa,a.wartosc)  inne
 
ON inne.umowa = e.umowa AND npd.stid = a.stid
 
WHERE  ((npd.sumnpd <> 0) OR (a.wartosc -  COALESCE(pd.sumpd, 0) - COALESCE(npd.sumnpd, 0) - COALESCE(inne.sumin, 0)) <> 0)
             AND a.protdt  BETWEEN 1101111 AND 1141111
 
ORDER BY e.umowa, a.stid;
 
edytowany 3x, ostatnio: michal2442, 2014-12-20 07:48
Umieść kod w treści posta w tagach &lt;code=sql&gt;&lt;/code&gt;, a w tagach tematu umieść informację o tym, jaki to silnik bazy. Inaczej wątek poleci do kosza. - somekind 2014-12-20 02:43
Dzięki. Tylko w tagach napisz o który silnik chodzi: MS SQL, Oracle, MySQL? - somekind 2014-12-20 12:50

Pozostało 580 znaków

2014-12-19 22:45
0

i jak ty sobie to wyobrażasz, że ktoś coś zrobi z tym zapytaniem??? Przede wszystkim potrzebny jest plan zapytania - google wie jak go pozyskać.
Przecież to nawet jakoś sensownie sformatowane nie jest

BTW kod daje się w treści posta


Chcesz pomocy - pokaż kod - abrakadabra źle działa z techniką.
edytowany 1x, ostatnio: abrakadaber, 2014-12-19 22:47

Pozostało 580 znaków

2014-12-22 08:35
0

Jak już napisał poprzednik nie jestem w stanie przebić się przez Twoje zapytanie. Możesz spróbować zamienić "or" na "and" w ten sposób (Prawa De Morgana):

zamiast:

A OR B

piszesz:

!(!A AND !B)

Jednakże nie jestem w stanie zagwarantować w jakim stopniu to poprawi wydajność w Twoim konkretnym przypadku.


Jeden zespół, tysiące możliwości!
nie poprawi, bo optymalizator wyprodukuje taki sam plan w tym przypadku. - Koziołek 2014-12-22 12:37

Pozostało 580 znaków

2014-12-22 12:42
0

Na początek sformatowane zapytanie:

SELECT DISTINCT e.umowa,
                b.statum,
                b.wartof,
                a.stid,
                a.statst,
                a.grupa,
                a.wartosc,
                COALESCE(pd.sumpd, 0) AS sumpd,
                COALESCE(npd.sumnpd, 0) AS sumnpd,
                COALESCE(inne.sumin, 0) AS sumin,
                (a.wartosc - COALESCE(pd.sumpd, 0) - COALESCE(npd.sumnpd, 0) - COALESCE(inne.sumin, 0)) AS roznica
FROM ((((((DROLEASEF2.PLST01PF a
           INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)
          INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)
         INNER JOIN DROLEASEF2.plfk09pf e ON e.umowa = b.umowa)
        INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr
        AND e.ipoz = f.poznbr)
       LEFT  JOIN
         (SELECT e.umowa,
                 b.statum,
                 b.wartof,
                 a.stid,
                 a.statst,
                 a.grupa,
                 a.wartosc,
                 SUM(f.winien - f.ma) AS sumpd
          FROM ((((DROLEASEF2.plst01pf a
                   INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)
                  INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)
                 INNER JOIN DROLEASEF2.plfk09pf e ON e.umowa = b.umowa)
                INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr
                AND e.ipoz = f.poznbr)
          WHERE e.invid < 0
            AND f.acc1 = '03081'
            AND EXISTS
              (SELECT g.stid, g.invid
               FROM DROLEASEF2.plst31pf g
               WHERE e.invid = g.invid
                 AND g.stid = a.stid
                 AND g.invid <0)
          GROUP BY e.umowa,
                   b.statum,
                   b.wartof,
                   a.stid,
                   a.statst,
                   a.grupa,
                   a.wartosc) pd ON pd.umowa = e.umowa
       AND pd.stid = a.stid)
      LEFT JOIN
        (SELECT e.umowa,
                b.statum,
                b.wartof,
                a.stid,
                a.statst,
                a.grupa,
                a.wartosc,
                SUM(f.winien - f.ma) AS sumnpd
         FROM ((((DROLEASEF2.plst01pf a
                  INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)
                 INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)
                INNER JOIN DROLEASEF2.plfk09pf e ON b.umowa = e.umowa)
               INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr
               AND e.ipoz = f.poznbr)
         WHERE f.acc1 = '03081'
           AND e.invid < 0
           AND NOT EXISTS
             (SELECT g.stid,
                     g.invid
              FROM DROLEASEF2.plst31pf g
              WHERE e.invid = g.invid
                AND g.stid = a.stid
                AND g.invid <0)
         GROUP BY e.umowa,
                  b.statum,
                  b.wartof,
                  a.stid,
                  a.statst,
                  a.grupa,
                  a.wartosc) npd ON npd.umowa = e.umowa
      AND npd.stid = a.stid)
LEFT JOIN
  (SELECT e.umowa,
          b.statum,
          b.wartof,
          a.stid,
          a.statst,
          a.grupa,
          a.wartosc,
          SUM(f.winien - f.ma) AS sumin
   FROM (((((DROLEASEF2.plst01pf a
             INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)
            INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)
           INNER JOIN DROLEASEF2.plfk09pf e ON b.umowa = e.umowa)
          INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr
          AND e.ipoz = f.poznbr)
         INNER JOIN DROLEASEF2.plfk07pf g ON g.docnbr = f.docnbr
         AND g.poznbr = f.poznbr)
   WHERE f.acc1 = '03081'
     AND g.zaptyp NOT IN (-1,
                          -3,
                          -4)
     AND e.invid < 0
   GROUP BY e.umowa,
            b.statum,
            b.wartof,
            a.stid,
            a.statst,
            a.grupa,
            a.wartosc) inne ON inne.umowa = e.umowa
AND npd.stid = a.stid
WHERE ((npd.sumnpd <> 0)
       OR (a.wartosc - COALESCE(pd.sumpd, 0) - COALESCE(npd.sumnpd, 0) - COALESCE(inne.sumin, 0)) <> 0)
  AND a.protdt BETWEEN 1101111 AND 1141111
ORDER BY e.umowa,
         a.stid;

// @somekind, możesz przpiąć do pierwszego posta i ten usunąć?

Pozostało 580 znaków

2014-12-22 12:50
0

Niepokoi mnie duża ilość inner join-ów, które się powtarzają. Jak dobrze licze masz trzykrotnie powtórzoną strukturę:

DROLEASEF2.PLST01PF a
           INNER JOIN DROLEASEF2.pled02pf b ON a.umowa = b.umowa)
          INNER JOIN DROLEASEF2.plst60pf c ON a.stid = c.stid)
         INNER JOIN DROLEASEF2.plfk09pf e ON e.umowa = b.umowa)
        INNER JOIN DROLEASEF2.plfk08pf f ON e.idoc = f.docnbr
        AND e.ipoz = f.poznbr

Pierwsze co bym tu zrobił to użycie Materialized Query Table jeszcze przed wykonaniem głównego raportu w celu wygenerowania raportu cześciowego. Następnie można na taki widok (bo jest to odpowiednich oraclowego materialized view) można nakładać ograniczenia, które będą już lżejsze.

Pozostało 580 znaków

2014-12-30 11:48
0

chopie, tak się nie pisze, bo komu potem będzie się chciało to rozczytywać po Tobie, żeby poprawić?
Nie jest przejrzyste. Lepiej robić po drodze tabelki tymczasowe i takie zapytanie zrobić w 3-4 krokach.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0