sql >> Database teknologi >  >> RDS >> PostgreSQL

Optimering af flere sammenføjninger

Der er altid 2 ting at overveje, når du optimerer forespørgsler:

  • Hvilke indekser kan bruges (du skal muligvis oprette indekser)
  • Hvordan forespørgslen er skrevet (du skal muligvis ændre forespørgslen for at tillade forespørgselsoptimereren at være i stand til at finde passende indekser og ikke genlæse data redundant)

Et par observationer:

  • Du udfører datomanipulationer, før du tilmelder dig dine dates. Som en generel regel vil dette forhindre en forespørgselsoptimer i at bruge et indeks, selvom det eksisterer. Du bør prøve at skrive dine udtryk på en sådan måde, at indekserede kolonner eksisterer uændret på den ene side af udtrykket.

  • Dine underforespørgsler filtrerer til det samme datointerval som generate_series . Dette er en duplikering, og det begrænser optimerens mulighed for at vælge den mest effektive optimering. Jeg formoder, at det kan være skrevet ind for at forbedre ydeevnen, fordi optimeringsprogrammet ikke var i stand til at bruge et indeks på datokolonnen (body_time )?

  • BEMÆRK :Vi vil faktisk meget gerne bruge et indeks på Body.body_time

  • ORDER BY inden for underforespørgslerne er i bedste fald overflødig. I værste fald kunne det tvinge forespørgselsoptimeringsværktøjet til at sortere resultatsættet, før det sluttede sig til; og det er ikke nødvendigvis godt for forespørgselsplanen. Anvend hellere kun bestilling lige til sidst for endelig visning.

  • Brug af LEFT JOIN i dine underforespørgsler er upassende. Forudsat at du bruger ANSI-konventioner for NULL adfærd (og det burde du være), enhver ydre slutter sig til envelope ville returnere envelope_command=NULL , og disse ville derfor blive udelukket af betingelsen envelope_command=? .

  • Underforespørgsler o og i er næsten identiske med undtagelse af envelope_command værdi. Dette tvinger optimeren til at scanne de samme underliggende tabeller to gange. Du kan bruge en pivottabel teknik til at slutte sig til dataene én gang og opdele værdierne i 2 kolonner.

Prøv følgende, der bruger pivotteknikken:

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

REDIGER :Tilføjet filter foreslået af Tom H.



  1. Hvordan opbygger man indeks i MySQL for at fremskynde denne forespørgsel?

  2. SQL Server – Dissekere det interne af sp_spaceused

  3. Simulerer group_concat MySQL-funktion i Microsoft SQL Server 2005?

  4. Sådan finder du minimumsværdier i kolonner