PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Optymalizacja wielu złączeń

Podczas optymalizacji zapytań zawsze należy wziąć pod uwagę 2 rzeczy:

  • Jakich indeksów można użyć (może być konieczne utworzenie indeksów)
  • Jak napisane jest zapytanie (może być konieczna zmiana zapytania, aby umożliwić optymalizatorowi zapytań znalezienie odpowiednich indeksów i uniknięcie ponownego odczytywania danych zbędnych)

Kilka obserwacji:

  • Manipulujesz datami, zanim dołączysz do swoich randek. Zasadniczo uniemożliwia to optymalizatorowi zapytań korzystanie z indeksu, nawet jeśli on istnieje. Powinieneś spróbować pisać swoje wyrażenia w taki sposób, aby indeksowane kolumny istniały niezmienione po jednej stronie wyrażenia.

  • Twoje podzapytania są filtrowane do tego samego zakresu dat, co generate_series . Jest to duplikacja i ogranicza możliwość wyboru przez optymalizatora najbardziej wydajnej optymalizacji. Podejrzewam, że mogło to zostać napisane w celu poprawy wydajności, ponieważ optymalizator nie był w stanie użyć indeksu w kolumnie daty (body_time )?

  • UWAGA :Właściwie bardzo chcielibyśmy użyć indeksu w Body.body_time

  • ORDER BY w podzapytaniach jest w najlepszym razie zbędne. W najgorszym przypadku może to zmusić optymalizator zapytań do posortowania zbioru wyników przed dołączeniem; i to niekoniecznie jest dobre dla planu zapytań. Zamiast tego stosuj zamawianie tylko na końcu w celu ostatecznego wyświetlenia.

  • Użycie LEFT JOIN w podzapytaniach jest nieodpowiednie. Zakładając, że używasz konwencji ANSI dla NULL zachowanie (a powinno być), każdy zewnętrzny dołącza do envelope zwróci envelope_command=NULL , a te w konsekwencji zostałyby wykluczone przez warunek envelope_command=? .

  • Zapytania podrzędne o i i są prawie identyczne, z wyjątkiem envelope_command wartość. Zmusza to optymalizatora do dwukrotnego skanowania tych samych tabel bazowych. Możesz użyć tabeli przestawnej technika jednokrotnego połączenia z danymi i podzielenia wartości na 2 kolumny.

Wypróbuj następujące, które wykorzystują technikę obrotu:

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

EDYTUJ :Dodano filtr sugerowany przez Toma H.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. flask-migrate nie może usunąć tabeli, ponieważ zależą od niej inne obiekty

  2. Wybieranie danych do tablicy Postgres

  3. Niestandardowa agregacja PostgreSQL dla średniej kołowej

  4. Postgres w wierszu poleceń z zewnętrznym edytorem nie uruchamiającym zapytania

  5. Migracja Railsów:Bigint na PostgreSQL wydaje się zawodzić?