sql >> Database >  >> RDS >> PostgreSQL

Meerdere samenvoegingen optimaliseren

Er zijn altijd 2 dingen waarmee u rekening moet houden bij het optimaliseren van zoekopdrachten:

  • Welke indexen kunnen worden gebruikt (mogelijk moet u indexen maken)
  • Hoe de query is geschreven (mogelijk moet u de query wijzigen om de query-optimizer in staat te stellen de juiste indexen te vinden en gegevens niet redundant opnieuw te lezen)

Een paar opmerkingen:

  • U voert datummanipulaties uit voordat u zich bij uw dates aansluit. Als algemene regel zal dit voorkomen dat een query-optimizer een index gebruikt, zelfs als deze bestaat. U moet proberen uw uitdrukkingen zo te schrijven dat geïndexeerde kolommen ongewijzigd bestaan ​​aan één kant van de uitdrukking.

  • Uw subquery's filteren naar dezelfde periode als generate_series . Dit is een duplicatie en het beperkt het vermogen van de optimser om de meest efficiënte optimalisatie te kiezen. Ik vermoed dat dit is geschreven om de prestaties te verbeteren, omdat de optimser geen index kon gebruiken in de datumkolom (body_time )?

  • OPMERKING :We zouden eigenlijk heel graag een index willen gebruiken op Body.body_time

  • ORDER BY binnen de subquery's is op zijn best overbodig. In het slechtste geval zou het de query-optimizer kunnen dwingen om de resultatenset te sorteren voordat deze wordt toegevoegd; en dat is niet per se goed voor het queryplan. Pas de bestelling liever pas aan het einde toe voor de uiteindelijke weergave.

  • Gebruik van LEFT JOIN in uw subquery's is ongepast. Ervan uitgaande dat u ANSI-conventies gebruikt voor NULL gedrag (en dat zou je ook moeten zijn), elke buitenste voegt zich bij envelope zou envelope_command=NULL . teruggeven , en deze zouden bijgevolg worden uitgesloten door de voorwaarde envelope_command=? .

  • Subquery's o en i zijn bijna identiek, behalve voor de envelope_command waarde. Dit dwingt de optimser om dezelfde onderliggende tabellen twee keer te scannen. U kunt een draaitabel gebruiken techniek om de gegevens één keer samen te voegen en de waarden in 2 kolommen te splitsen.

Probeer het volgende, waarbij gebruik wordt gemaakt van de spiltechniek:

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

BEWERKEN :Filter toegevoegd voorgesteld door Tom H.



  1. Waarom vertraagt ​​de hogere LIMIT-offset van MYSQL de query?

  2. check beschikbaarheid van een kamer met SQL

  3. Creëer multi-level JSON met PHP en MySQL

  4. Apache NiFi