sql >> Databasteknik >  >> RDS >> PostgreSQL

Optimera flera kopplingar

Det finns alltid två saker att tänka på när du optimerar frågor:

  • Vilka index kan användas (du kan behöva skapa index)
  • Hur frågan skrivs (du kan behöva ändra frågan för att tillåta frågeoptimeraren att kunna hitta lämpliga index och inte läsa om data redundant)

Några observationer:

  • Du utför datummanipulationer innan du går med på dina dejter. Som en allmän regel kommer detta att förhindra en frågeoptimerare från att använda ett index även om det finns. Du bör försöka skriva dina uttryck på ett sådant sätt att indexerade kolumner finns oförändrade på ena sidan av uttrycket.

  • Dina underfrågor filtreras till samma datumintervall som generate_series . Detta är en dubblering, och det begränsar optimerarens möjlighet att välja den mest effektiva optimeringen. Jag misstänker att det kan ha skrivits in för att förbättra prestandan eftersom optimeraren inte kunde använda ett index i datumkolumnen (body_time )?

  • OBS :Vi skulle faktiskt väldigt gärna vilja använda ett index på Body.body_time

  • ORDER BY inom underfrågorna är i bästa fall överflödig. I värsta fall kan det tvinga frågeoptimeraren att sortera resultatuppsättningen innan den går med; och det är inte nödvändigtvis bra för frågeplanen. Använd hellre bara beställning direkt i slutet för slutlig visning.

  • Användning av LEFT JOIN i dina underfrågor är olämpligt. Förutsatt att du använder ANSI-konventioner för NULL beteende (och det borde du vara), vilket som helst yttre ansluter till envelope skulle returnera envelope_command=NULL , och dessa skulle följaktligen uteslutas av villkoret envelope_command=? .

  • Underfrågor o och i är nästan identiska med undantag för envelope_command värde. Detta tvingar optimeraren att skanna samma underliggande tabeller två gånger. Du kan använda en pivottabell teknik för att ansluta till data en gång och dela upp värdena i 2 kolumner.

Prova följande som använder pivottekniken:

SELECT  p.period,
        /*The pivot technique in action...*/
        SUM(
        CASE WHEN envelope_command = 1 THEN body_size
        ELSE 0
        END) AS Outbound,
        SUM(
        CASE WHEN envelope_command = 2 THEN body_size
        ELSE 0
        END) AS Inbound
FROM    (
        SELECT  date '2009-10-01' + s.day AS period
        FROM    generate_series(0, date '2009-10-31' - date '2009-10-01') AS s(day)
        ) AS p 
        /*The left JOIN is justified to ensure ALL generated dates are returned
          Also: it joins to a subquery, else the JOIN to envelope _could_ exclude some generated dates*/
        LEFT OUTER JOIN (
        SELECT  b.body_size,
                b.body_time,
                e.envelope_command
        FROM    body AS b 
                INNER JOIN envelope e 
                  ON e.message_id = b.message_id 
        WHERE   envelope_command IN (1, 2)
        ) d
          /*The expressions below allow the optimser to use an index on body_time if 
            the statistics indicate it would be beneficial*/
          ON d.body_time >= p.period
         AND d.body_time < p.period + INTERVAL '1 DAY'
GROUP BY p.Period
ORDER BY p.Period

REDIGERA :Lade till filter föreslagit av Tom H.



  1. Att få det sista ordet från en Postgres-sträng, deklarativt

  2. Hur Div() fungerar i PostgreSQL

  3. Använda kolumnalias i fältet Sales Order Grid

  4. Paket:cx_Oracle för Python 3.5, windows64 bit. Oracle 11.2.0.1.0